Add tcpdump and tcpslice source code to /usr/src/contrib
authorDavid Greenman <dg@Root.COM>
Wed, 24 Mar 1993 00:00:00 +0000 (00:00 +0000)
committerDavid Greenman <dg@Root.COM>
Wed, 24 Mar 1993 00:00:00 +0000 (00:00 +0000)
This patch adds the source code for tcpdump and tcpslice to
/usr/src/contrib.  These are based upon the 2.2.1 release of bpf.

The source code has been reworked into the standard bsd source
code tree format, new Makefiles have also been written.  This is being
added to the source tree as it is highly kernel dependent and this is
the version that matches the current 386bsd kernel.

NOTE: The patch for the top level makefile (/usr/src/Makefile)
is being delayed for a latter patch, thus there will be one large patch
to this file, instead of many small patches.

AUTHOR: David Greenman (davidg@implode.rain.com)
AUTHOR: Rodney W. Grimes (rgrimes@agora.rain.com)
386BSD-Patchkit: patch00114

104 files changed:
usr/src/contrib/Makefile [new file with mode: 0644]
usr/src/contrib/Makefile.inc [new file with mode: 0644]
usr/src/contrib/gzip/COPYING [new file with mode: 0644]
usr/src/contrib/gzip/ChangeLog [new file with mode: 0644]
usr/src/contrib/gzip/Makefile [new file with mode: 0644]
usr/src/contrib/gzip/NEWS [new file with mode: 0644]
usr/src/contrib/gzip/README [new file with mode: 0644]
usr/src/contrib/gzip/THANKS [new file with mode: 0644]
usr/src/contrib/gzip/TODO [new file with mode: 0644]
usr/src/contrib/gzip/algorithm.doc [new file with mode: 0644]
usr/src/contrib/gzip/bits.c [new file with mode: 0644]
usr/src/contrib/gzip/crypt.c [new file with mode: 0644]
usr/src/contrib/gzip/crypt.h [new file with mode: 0644]
usr/src/contrib/gzip/deflate.c [new file with mode: 0644]
usr/src/contrib/gzip/getopt.c [new file with mode: 0644]
usr/src/contrib/gzip/getopt.h [new file with mode: 0644]
usr/src/contrib/gzip/gzexe [new file with mode: 0644]
usr/src/contrib/gzip/gzexe.1 [new file with mode: 0644]
usr/src/contrib/gzip/gzip.1 [new file with mode: 0644]
usr/src/contrib/gzip/gzip.c [new file with mode: 0644]
usr/src/contrib/gzip/gzip.h [new file with mode: 0644]
usr/src/contrib/gzip/inflate.c [new file with mode: 0644]
usr/src/contrib/gzip/lzw.c [new file with mode: 0644]
usr/src/contrib/gzip/lzw.h [new file with mode: 0644]
usr/src/contrib/gzip/match.S [new file with mode: 0644]
usr/src/contrib/gzip/revision.h [new file with mode: 0644]
usr/src/contrib/gzip/tailor.h [new file with mode: 0644]
usr/src/contrib/gzip/trees.c [new file with mode: 0644]
usr/src/contrib/gzip/unlzw.c [new file with mode: 0644]
usr/src/contrib/gzip/unpack.c [new file with mode: 0644]
usr/src/contrib/gzip/unzip.c [new file with mode: 0644]
usr/src/contrib/gzip/util.c [new file with mode: 0644]
usr/src/contrib/gzip/zcmp [new file with mode: 0644]
usr/src/contrib/gzip/zcmp.1 [new file with mode: 0644]
usr/src/contrib/gzip/zdiff [new file with mode: 0644]
usr/src/contrib/gzip/zforce [new file with mode: 0644]
usr/src/contrib/gzip/zforce.1 [new file with mode: 0644]
usr/src/contrib/gzip/zip.c [new file with mode: 0644]
usr/src/contrib/gzip/zmore [new file with mode: 0644]
usr/src/contrib/gzip/zmore.1 [new file with mode: 0644]
usr/src/contrib/gzip/znew [new file with mode: 0644]
usr/src/contrib/gzip/znew.1 [new file with mode: 0644]
usr/src/contrib/tcpdump/Makefile [new file with mode: 0644]
usr/src/contrib/tcpdump/Makefile.inc [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/Makefile [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/VERSION [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/addrtoname.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/addrtoname.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/appletalk.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/bootp.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/bpf_dump.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/bpf_image.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/etherent.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/etherent.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/etherproto.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/extract.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/gencode.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/gencode.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/inet.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/interface.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/md.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/md.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/mib.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/nametoaddr.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/nametoaddr.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/ntp.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/optimize.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/os.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/os.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/ospf.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/pcap.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-arp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-atalk.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-bootp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-domain.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-egp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-ether.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-fddi.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-icmp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-ip.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-nfs.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-ntp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-null.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-ospf.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-ppp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-rip.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-sl.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-snmp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-sunrpc.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-tcp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-tftp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/print-udp.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/savefile.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/savefile.h [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/tcpdump.1 [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/tcpdump.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/tcpgram.y [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/tcplex.l [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpdump/util.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpslice/Makefile [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpslice/gwtm2secs.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpslice/search.c [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpslice/tcpslice.1 [new file with mode: 0644]
usr/src/contrib/tcpdump/tcpslice/tcpslice.c [new file with mode: 0644]

diff --git a/usr/src/contrib/Makefile b/usr/src/contrib/Makefile
new file mode 100644 (file)
index 0000000..9753a96
--- /dev/null
@@ -0,0 +1,7 @@
+#      @(#)Makefile    0.1 (RGrimes) 4/7/93
+
+SUBDIR=        gzip tcpdump
+
+# Not ported: isode
+
+.include <bsd.subdir.mk>
diff --git a/usr/src/contrib/Makefile.inc b/usr/src/contrib/Makefile.inc
new file mode 100644 (file)
index 0000000..9489995
--- /dev/null
@@ -0,0 +1,3 @@
+#      @(#)Makefile.inc        5.1 (Berkeley) 5/11/90
+
+BINDIR?=       /usr/local/bin
diff --git a/usr/src/contrib/gzip/COPYING b/usr/src/contrib/gzip/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/usr/src/contrib/gzip/ChangeLog b/usr/src/contrib/gzip/ChangeLog
new file mode 100644 (file)
index 0000000..6ad254b
--- /dev/null
@@ -0,0 +1,378 @@
+Thu Mar 18 18:56:43 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.7
+         Allow zmore to read from standard input (like more).
+         Support the 68000 (Atari ST) in match.S.
+         Retry partial writes (required on Linux when gzip is suspended in
+           a pipe).
+         Allow full pathnames and renamings in gzexe.
+         Don't let gzexe compress setuid executables or gzip itself.
+         Added vms/Makefile.gcc for gcc on the Vax.
+         Give a pointer to Solaris and VMS executables of gzip in README.
+         Allow installation of binaries and shell scripts in different dirs.
+         Do not use alloca on the Cray.
+         Provide strspn and strcspn if string.h does not exist.
+         Define O_CREAT and O_EXCL from FCREAT and FEXCL if necessary.
+         Remove gzip.doc in make realclean.
+         Fixed many typos. (Corrections to my English are welcome.)
+         Put "make manext=l install" at the correct place in INSTALL.
+         Fix incorrect examples in INSTALL and give more examples.
+         Include zdiff.1 for install and uninstall.
+         Allows complex PAGER variable in zmore (e.g.: PAGER="col -x | more")
+         Avoid warning on unused indfound in getopt.c.
+         Cast memset arg to void* (required by some buggy compilers).
+         Include sys/types.h before dirent.h in acgeneral.m4.
+         Fix acgeneral.m4 AC_COMPILE_CHECK to avoid warnings.
+         Don't use alloca.c with gcc. (One NeXT user did not have alloca.h).
+         Change all error messages according to GNU standards.
+         Restore time stamp only if off by more than one minute.
+         Allow installation of zcat as gzcat.
+         Suppress help message  and send compressed data to the terminal when
+           gzip is invoked without parameters and without redirection.
+          (Explicit request from Noah Friedman.)
+         Add compile option GNU_STANDARD to respect the GNU coding standards:
+           with -DGNU_STANDARD, behave as gzip even if invoked under the
+           name gunzip. (Complaints to /dev/null or the FSF, not to me!)
+
+Fri Mar 10 13:27:18 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.6
+         Let gzexe detect executables that are already gzexe'd.
+         Don't try restoring record format on VMS (the simple 1.0.5 code
+           worked correctly only on fixed-512 files). Suppress text_mode.
+         Added asm version for 68000 in amiga/match.a.
+         Use asm version for Atari TT.
+         Fix "make clean" in vms/Makefile.vms.
+         For OS/2, assume HPFS by default, add flag OS2FAT if necessary.
+         Fixed some bugs in zdiff and define zcmp as a link to zdiff.
+         Added zdiff.1
+         Remove configure hack for NeXT; add general fix to autoconf instead
+         Do not strip a ".z" extension if this results in an empty name.
+         Avoid array overflow in get_prefix() for extensions > 10 chars.
+         Accept either q or e to quit zmore.
+         In zmore, try restoring tty mode in all cases.
+         Use Motorola style for match.S on the NeXT.
+         configure.in: unsetenv *hangs* with the Siemens csh...
+         Update vms/gzip.hlp.
+
+Thu Mar 4 14:13:34 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.5
+         For VMS, restore the file type for variable record format, otherwise
+           extract in fixed length format (not perfect, but better than
+            forcing all files to be in stream_LF format).
+         Use "-z" suffix for VMS.
+         Use only .z, .*-z, .tgz, .taz as valid gzip extensions; update
+          zforce accordingly.
+         Allow a version number in input file names for VMS.
+         Added sample program zread.c.
+         Fix "make check" for some implementations of /bin/sh.
+         Don't rely on stat() for filenames with extension > 3 chars
+           on MSDOS, OS2 and Atari.
+         Garbage collect files in /tmp created by gzexe.
+         Quote $opt in znew.
+         Use TOUCH env variable in znew if it exists.
+         Better error message for gunzip on empty or truncated file.
+         Allow prototypes in getopt.h when __STDC__ defined but 0.
+         Added "make clean" in vms/Makefile.vms.
+         Removed -g from default CFLAGS (with Noah's permission!)
+         Avoid too many HAVE_xxx_H for most systems; use common defaults.
+         Moved default Atari flags into tailor.h for consistency.
+         Use memzero() to clear the hash table.
+         Update vms/gzip.hlp to reflect the VMS behavior.
+         Fix OS_CODE (to fit in a byte).
+         Add utime.h for the Amiga.
+         Add gcc support for the Amiga.
+         Work around incorrect dirent.h for NeXT 2.0.
+         Added Makefile entry for Coherent.
+
+Fri Feb 22 11:20:49 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.4
+         Added optimized asm version for 68020.
+         Add support for DJGPP.
+         Add support for the Atari ST.
+         Added zforce to rename gzip'ed files with truncated names.
+         Do not install with name uncompress (some systems rely on the
+           absence of any check in the old uncompress).
+         Added missing function (fcfree) in msdos/tailor.c
+         Let gunzip handle .tgz files, and let gzip skip them.
+         Added 'stty min 1' in zmore for SysV and fixed trap code.
+         Suppress .PHONY in Makefile.in, which breaks old makes.
+         Added documentation about pcat and unpack in INSTALL.
+         Add cast to getenv for systems without stdlib.h.
+         Use VAXC instead of VMS to avoid confusion for gcc.
+         Add -K to znew.1.
+         Add gzexe.1.
+         Try preserving file permissions in gzexe.
+         Added -d option for gzexe.
+         Guard against spaces in file names in gzexe.
+         Use CMP env. variable in zcmp.
+         Return a warning exit status for gzip of file with .z suffix.
+         Suppress usage of d_ino which is not portable to all systems.
+         Use #ifdef instead of #if for consistency.
+         For VMS, use "cc util.c" instead of "cc util" (pb with logical names)
+         Added utime() for Amiga.
+         Renamed gzcat.1 as zcat.1.
+         Include fcntl.h for Amiga (for read and write).
+         For VMS, add definition of symbols and links in the makefiles.
+         Give a VMS look to vms/gzip.hlp.
+         Save the original name only when necessary.
+         Add a mode parameter for open in read mode (required by VMS).
+         For VMS, remove the version suffix from the original name.
+         Accept both / and \ as path separator for MSDOS.
+         Let gunzip extract stored .zip files correctly.
+         Added warning about VFC format in vms/gzip.hlp.
+         In znew, skip a bad file but process the others.
+         Cleanup tailor.h.
+         Use GZIP_OPT for VMS to avoid conflict with program name.
+         Added description of GZIP variable in gzip.texi.
+
+Thu Feb 11 17:21:32 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.3
+         Add -K option for znew to keep old .Z files if smaller.
+         Add -q option (quiet) to cancel -v in GZIP env variable.
+          For Turbo C, normalize pointers before freeing them.
+          Add more safety checks in add_envopt().
+          Add do_exit() for uniform exit path (always free memory).
+          Reduce MAX_PATH_LEN for MSDOS.
+         Include sys/types.h before signal.h
+         Avoid strdup, the NeXT does not have it.
+          Made gzexe safer on systems with filename limitation to 14 chars.
+
+Fri Feb  10 09:45:49 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.2
+         Added env variable GZIP for default options.
+         Added support for the Amiga.
+         znew now keeps the old .Z if it is smaller than the .z file.
+         Added gzexe to compress rarely used executables.
+         Reduce memory usage when using static allocation (no DYN_ALLOC).
+         Better separation of warning and error return codes.
+         Fix unlzw.c to make DYN_ALLOC and MAXSEG_64K independent options.
+         Allow INBUFSIZ to be >= 32K in unlzw (don't use sign of rsize)
+         Generate tar file in old format to avoid problems with old systems.
+         Preserve time stamp in znew -P if touch -r works.
+         Use ${PAGER-more} instead of ${PAGER:-more} in zmore.
+         Do not use unsigned instead of mode_t.
+         Better error message for trailing garbage in .z file; ignore this
+          garbage on VMS.
+         In zmore, use icanon instead of -cbreak on SYSV.
+         Add trap handler in zmore.
+         Use char* instead of void* for non STDC compilers.
+         Added makefile entry for Xenix on 286.
+         Return an error code when existing file was not overwritten.
+         Use prototype of lzw.h for lzw.c.
+         Fix znew with -P option alone.
+         Give warning for directories even without -v.
+         Close output file before unlink() in case of error.
+         Suppress all target dependent ifdef from the portable files.
+         Free all dynamically allocated variables upon exit.
+
+Thu Feb 4 18:23:56 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0.1
+         Fixed some trivial errors in msdos/Makefile.bor
+
+Thu Feb 4 10:00:59 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * version 1.0
+         gzip now runs on Vax/VMS (Amiga support will come in next version).
+         Do not overwrite files without -f when using /bin/sh.
+          Support the test option -t for compressed (.Z) files.
+         Flush output for bad compressed files. Add warning in README.
+         Added makefiles for MSDOS.
+         Don't rely on presence of csh in configure
+         Added gunzip.1 and gzcat.1.
+         Updated znew.1.
+         Check reserved flags in unlzw().
+         Return dummy value in main to avoid lint warning.
+         Define OF in lzw.h for lint.
+         Allow both "znew -v -t" and "znew -vt".
+         Don't overwrite the output file name for multiple parts.
+         Echo just a warning if configure is out of date.
+         Use ; instead of , in trees.c (confuses the SAS Amiga compiler).
+         In INSTALL, document "DEFS='-DM_XENIX' ./configure".
+         Use OTHER_PATH_SEP for more portability (DOS, OS2, VMS, AMIGA).
+         Make all directories world writable for broken versions of tar.
+         Use gzip -cd instead of zcat in zmore, zcmp, zdiff.
+         Don't use GNU tar for distributions, some systems can't untar.
+         Do not exit() for gzip --version.
+
+Mon Jan 26 10:26:42 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.8.2
+         Avoid 'far' declarations for MSDOS.
+         Use test -f instead of test -x in configure.in (for Ultrix)
+         Add empty else part to if in Makefile.in for broken shells.
+         Use NO_UNDERLINE instead of UNDERLINE (pb with Linux cpp)
+         Accept continuation files with -ff (for damage recovery)
+         Small patch to Makefile.os2
+         Use memzero instead of bzero to avoid potential conflicts
+         Document restriction on extraction of zip files.
+         Fix quoting in ACL_HAVE_SHELL_HACK.
+          Do not check file size on MSDOS because of bug in DIET.
+         Allow zcat on a file with multiple links.
+         Add fix in inflate.c for compatibility with pkzip 2.04c.
+         Release gzip in tar.z and tar format. (No tar.Z).
+
+Fri Jan 22 10:04:13 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.8.1
+         Fixed Makefile.os2
+         Fixed #if directives that TurboC does not like.
+         Don't rely on uncompress in znew, use gzip -d.
+         Add the pipe option -P in znew.
+         Add some more ideas in TODO.
+         Support both NDIR and SYSNDIR.
+
+Sat Jan  21 15:46:38 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.8
+         Support unpack.
+         Check for _match.o in configure.in in addition to return status.
+         Include <sys/types.h> in zip.c
+         Define local variables and functions as local.
+         Accept more alternative names for the program (pcat, gzcat, ...).
+         Accept .exe as well as .EXE.
+         Uncompress files with multiple links only with -f.
+         Better error message for gunzip of non-existent file.z.
+         Fix the entry for /etc/magic in INSTALL.
+         Use AC_HAVE_HEADERS uniformly instead of special macros.
+         Install the man pages as .1 by default instead of .l.
+         Document crypt++.el in README.
+         Fix for unlzw() on 16-bit machines (bitmask must be unsigned).
+         Complain if input and output files are identical.
+         Create a correct output name for files of exactly 13 chars.
+         Do not overwrite CPP if set
+         Check for i386 before trying to assemble match.s
+         Check for underline in external name before assembling
+         Add patch for tar 1.11.1.
+
+Mon Jan  5 10:16:24 1993  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.7
+         Use "make check" instead of "make test".
+         Do not rely on dirname in znew.
+         Keep time stamp and pass options to gzip in znew.
+         Rename .l files back to .1 to avoid conflict with lex
+         Do not create .z.z files with gzip -r.
+         Use nice_match in match.asm
+         Unroll loops in deflate.c
+         Do not attempt matches beyond the window end
+         Allow again gunzip .zip files (was working in 0.5)
+         Allow again compilation with TurboC 2.0 (was working in 0.4)
+
+Tue Dec 30 20:00:19 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.6
+         The .z extension is used by pack, not compact (README, gzip.1)
+         Accept gzcat in addition to zcat.
+         Use PAGER in zmore if defined.
+         Man pages for /usr/local/man/manl should have extension .l.
+         Don't redefine bzero on the NeXT
+         Allow incomplete Huffman table if there is only one code.
+         Don't lookahead more than 7 bits (caused premature EOF).
+         Added "make test" to check for compiler bugs.
+         Don't rely on `i386`; try to assemble directly
+         Change magic header to avoid conflict with freeze 1.x.
+         Added entry for /etc/magic in INSTALL.
+         Do not destroy an input .zip file with more than one member.
+         Display "untested" instead of "OK" for gzip -t foo.Z
+         With -t, skip stdin in .Z format
+         Allow multiple compressed members in an input file.
+         Ignore a zero time stamp.
+         Made znew safer.
+
+Tue Dec 29 10:00:19 1992   Noah Friedman  (friedman@gnu.ai.mit.edu)
+
+         Added test for #!/bin/sh in configure.in.
+         Fix some references to $srcdir in Makefile.in
+
+Mon Dec 21 17:33:35 1992  Jean-Loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.5
+         Put RCS ids in all files.
+         Added znew to recompress old .Z files with gzip.
+         Avoid "already .z suffix" messages for -r and no -v.
+         Put back check for d_ino in treat_dir().
+         Use HAVE_STRING_H instead of USG.
+         Added os2/Makefile.os2
+         Use SYSUTIME on OS/2.
+         Info dir is $(prefix)/info, not $(prefix)/lib/info.
+         Support long options, added getopt and alloca
+         Support -V and -t
+         Reorder configure.in according to suggestions in autoconf.info
+         Allow links when not removing original file
+         Allow either .z or .Z in zdiff
+
+Wed Nov 25 11:40:04 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.4.1
+         Save only the original base name, don't include any directory prefix.
+         Don't use HAVE_LONG_FILE_NAMES (support multiple file system types).
+         Fix declaration of abort_gzip in gzip.h.
+         Include unistd.h when it exists to avoid warnings with gcc -Wall.
+
+Mon Nov 23 12:39:01 1992    Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.4
+          Lots of cleanup
+         Use autoconf generated 'configure'
+          Fixed the NO_MULTIPLE_DOTS code
+          Fixed the save_orig_name code
+          Support for MSDOS (Turbo C)
+
+Thu Nov 19 15:18:22 1992    Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Beta version 0.3
+         Added auto configuration. Just type "make" now.
+         Don't overwrite compress by default in "make install". Use
+           "make install_compress" to overwrite.
+         Add match.s for 386 boxes.
+         Added documentation in texinfo format.
+         Provide help for "gunzip" invoked without redirected input.
+         Save original file name when necessary.
+         Support OS/2 (Kai-Uwe Rommel).
+
+Tue Nov 17 14:32:53 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.2.4
+         Return 0 in get_istat() when ok (caused error with zcat).
+         Don't update crc on compressed data (caused crc errors on
+           large files).
+
+Fri Nov 13 15:04:12 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.2.3
+         Initialize rsize in unlzw.c
+         Initialize ofd for zcat.
+         Do not use volatile ifname as argument of treat_dir.
+         Add -1 to -9 in gzip.1.
+
+Sat Oct 31 18:30:00 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.2.2.
+         Fix error messages.
+         Accept gunzip on zip files.
+
+Sat Oct 31 17:15:00 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.2.1
+         Use ctype.h in util.c (problem on SysV).
+         Create BINDIR if it does not exist.
+         Use cc by default.
+         Added zcmp, zmore, zdiff.
+         Fixed the man page gzip.1.
+
+Sat Oct 31 17:00:00 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.2
+         Fixed compilation problems with gcc
+
+Sat Oct 31 12:46:00 1992  Jean-loup Gailly  (jloup@chorus.fr)
+
+       * Alpha version 0.1 released (under time pressure), so it's not
+         much tested, sorry.
+
diff --git a/usr/src/contrib/gzip/Makefile b/usr/src/contrib/gzip/Makefile
new file mode 100644 (file)
index 0000000..04f07b6
--- /dev/null
@@ -0,0 +1,22 @@
+#       @(#)Makefile    5.3 (Berkeley) 5/12/90
+
+PROG=  gzip
+SRCS=  gzip.c zip.c deflate.c trees.c bits.c unzip.c inflate.c util.c \
+       crypt.c lzw.c unlzw.c unpack.c getopt.c match.S
+MAN1=  gzip.0 zcmp.0 zmore.0 znew.0 zforce.0 gzexe.0
+CFLAGS+=-DASMV -DHAVE_UNISTD_H=1 -DDIRENT=1
+MLINKS=        zcmp.1 zdiff.1  gzip.1 gunzip.1  gzip.1 zcat.1
+
+afterinstall:
+       install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+          ${.CURDIR}/zforce ${.CURDIR}/gzexe ${.CURDIR}/znew \
+          ${.CURDIR}/zmore ${.CURDIR}/zdiff ${.CURDIR}/zcmp \
+          ${DESTDIR}${BINDIR}
+
+match.o: match.S
+       $(CPP) ${.CURDIR}/match.S >_match.s
+       $(CC) -c _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+.include <bsd.prog.mk>
diff --git a/usr/src/contrib/gzip/NEWS b/usr/src/contrib/gzip/NEWS
new file mode 100644 (file)
index 0000000..75a184b
--- /dev/null
@@ -0,0 +1,212 @@
+Current Version: 1.0.7
+See the file ChangeLog for the details of all changes.
+
+User visible changes from 1.0.6 to 1.0.7.
+
+o Allow zmore to read from standard input (like more).
+
+o Support the 68000 (Atari ST) in match.S.
+
+o Retry partial writes (required on Linux when gzip is suspended in a pipe).
+
+o Allow full pathnames and renamings in gzexe.
+  Don't let gzexe compress setuid executables or gzip itself.
+       
+o Added vms/Makefile.gcc for gcc on the Vax.
+
+o Allow installation of binaries and shell scripts in different dirs.
+
+o Allows complex PAGER variable in zmore (e.g.: PAGER="col -x | more")
+
+o Allow installation of zcat as gzcat.
+
+o Several small changes for portability to old or weird systems.
+
+o Suppress help message and send compressed data to the terminal when
+  gzip is invoked without parameters and without redirection.
+
+o  Add compile option GNU_STANDARD to respect the GNU coding standards:
+   with -DGNU_STANDARD, behave as gzip even if invoked under the name gunzip.
+
+(I don't like the last two changes, which were requested by the FSF.)
+
+
+User visible changes from 1.0.5 to 1.0.6.
+
+o Let gzexe detect executables that are already gzexe'd.
+
+o Keep file attributes in znew and gzexe if cpmod is available.
+
+o Don't try restoring record format on VMS (1.0.5 did not work correctly)
+
+o Added asm version for 68000 in amiga/match.a.
+  Use asm version for Atari TT and NeXT.
+
+o For OS/2, assume HPFS by default, add flag OS2FAT if necessary.
+
+o Fixed some bugs in zdiff and define zcmp as a link to zdiff.
+
+
+User visible changes from 1.0.4 to 1.0.5.
+
+o For VMS, restore the file type for variable record format, otherwise
+    extract in fixed length format (not perfect, but better than
+    forcing all files to be in stream_LF format).
+
+o For VMS, use "-z" default suffix and accept a version number in file names.
+
+o For Unix, allow compression of files with name ending in 'z'. Use only
+  .z, .*-z, .tgz, .taz as valid gzip extensions. In the last two cases,
+  extract to .tar by default.
+
+o On some versions of MSDOS, files with a 3 character extension could not
+  be compressed.
+
+o Garbage collect files in /tmp created by gzexe.
+
+o Fix the 'OS code' byte in the gzip header.
+
+o For the Amiga, add the missing utime.h and add support for gcc.
+
+
+User visible changes from 1.0.3 to 1.0.4.
+
+o Added optimized asm version for 68020.
+
+o Add support for DJGPP.
+       
+o Add support for the Atari ST.
+
+o Added zforce to rename gzip'ed files with truncated names.
+
+o Do not install with name uncompress (some systems rely on the
+  absence of any check in the old uncompress).
+
+o Added missing function (fcfree) in msdos/tailor.c
+
+o Let gunzip handle .tgz files, and let gzip skip them.
+
+o Added -d option (decompress) for gzexe and try preserving file permissions.
+
+o Suppress all warnings with -q.
+
+o Use GZIP_OPT for VMS to avoid conflict with program name.
+
+o ... and many other small changes (see ChangeLog)
+
+
+User visible changes from 1.0.2 to 1.0.3
+
+o Added -K option for znew to keep old .Z files if smaller
+
+o Added -q option (quiet) to cancel -v in GZIP env variable.
+
+o Made gzexe safer on systems with filename limitation to 14 chars.
+
+o Fixed bugs in handling of GZIP env variable and incorrect free with Turbo C.
+
+
+User visible changes from 1.0.1 to 1.0.2
+
+o Added env variable GZIP for default options. Example:
+   for sh:   GZIP="-8 -v"; export GZIP
+   for csh:  setenv GZIP "-8 -v"
+
+o Added support for the Amiga.
+
+O znew now keeps the old .Z if it is smaller than the .z file.
+  This can happen for some large and very redundant files.
+
+o Do not complain about trailing garbage for record oriented IO (Vax/VMS).
+  This implies however that multi-part gzip files are not supported
+  on such systems.
+
+o Added gzexe to compress rarely used executables.
+
+o Reduce memory usage (required for MSDOS and useful on all systems).
+
+o Preserve time stamp in znew -P (pipe option) if touch -r works.
+
+
+User visible changes from 1.0 to 1.0.1
+
+o fix trivial errors in the Borland makefile (msdos/Makefile.bor)
+
+
+User visible changes from 0.8.2 to 1.0
+
+o gzip now runs on Vax/VMS
+
+o gzip will not not overwrite files without -f when using /bin/sh in
+  background.
+
+o Support the test option -t for compressed (.Z) files.
+  Allow some data recovery for bad .Z files.
+
+o Added makefiles for MSDOS (Only tested for MSC, not Borland).
+
+o still more changes to configure for several systems
+
+
+User visible changes from 0.8.1 to 0.8.2:
+
+o yet more changes to configure for Linux and other systems
+
+o Allow zcat on a file with multiple links.
+
+
+User visible changes from 0.8 to 0.8.1:
+
+o znew has now a pipe option -P to reduce the disk space requirements,
+  but this option does not preserve timestamps.
+
+o Fixed some #if directives for compilation with TurboC.
+
+
+User visible changes from 0.7 to 0.8:
+
+o gzip can now extract .z files created by 'pack'.
+
+o configure should no longer believe that every machine is a 386
+
+o Fix the entry for /etc/magic in INSTALL.
+
+o Add patch for GNU tar 1.11.1 and a pointer to crypt++.el
+
+o Uncompress files with multiple links only with -f.
+
+o Fix for uncompress of .Z files on 16-bit machines
+
+o Create a correct output name for file names of exactly N-1 chars when
+  the system has a limit of N chars.
+
+
+User visible changes from 0.6 to 0.7:
+
+o Use "make check" instead of "make test".
+
+o Keep time stamp and pass options to gzip in znew.
+
+o Do not create .z.z files with gzip -r.
+
+o Allow again gunzip .zip files (was working in 0.5)
+
+o Allow again compilation with TurboC 2.0 (was working in 0.4)
+
+
+User visible changes form 0.5 to 0.6:
+
+o gunzip reported an error when extracting certain .z files. The .z files
+  produced by gzip 0.5 are correct and can be read by gunzip 0.6.
+
+o gunzip now supports multiple compressed members within a single .z file.
+
+o Fix the check for i386 in configure.
+
+o Added "make test" to check for compiler bugs. (gcc -finline-functions
+  is broken at least on the NeXT.)
+
+o Use environment variable PAGER in zmore if it is defined.
+
+o Accept gzcat in addition to zcat for people having /usr/bin before
+  /usr/local/bin in their path.
diff --git a/usr/src/contrib/gzip/README b/usr/src/contrib/gzip/README
new file mode 100644 (file)
index 0000000..0c04669
--- /dev/null
@@ -0,0 +1,93 @@
+This is the file README for the gzip distribution, version 1.0.7.
+
+gzip (GNU zip) is a compression utility designed to be a replacement
+for 'compress'. Its main advantages over compress are much better
+compression and freedom from patented algorithms.  The GNU Project
+uses it as the standard compression program for its system.
+
+gzip currently uses by default the LZ77 algorithm used in zip 1.9 (the
+portable pkzip compatible archiver). The gzip format was however
+designed to accommodate several compression algorithms.
+
+gunzip can currently decompress files created by gzip, zip (with
+restrictions), compress or pack. (The SCO 'compress -H' format will be
+supported in a future version.)  The detection of the input format is
+automatic.  When using the first two formats, gunzip checks a 32 bit
+CRC. For pack, gunzip checks the uncompressed length.  The 'compress'
+format was not designed to allow consistency checks. However gunzip is
+sometimes able to detect a bad .Z file because there is some
+redundancy in the .Z compression format. If you get an error when
+uncompressing a .Z file, do not assume that the .Z file is correct
+simply because the standard uncompress does not complain.  This
+generally means that the standard uncompress does not check its input,
+and happily generates garbage output.
+
+gzip produces files with a .z extension. This was chosen to mimic the
+'compress' .Z extension. Using exactly the same extension would have
+caused too much confusion. Using a completely different extension
+would have forced changes in other programs such as GNU tar (which has
+a -z option).  The .z extension is already used by the 'pack'
+Huffman encoder, but gunzip is able to decompress packed files.
+
+Several planned features are not yet supported (see the file TODO).
+See the file INSTALL for installation instructions. See the file NEWS
+for a summary of changes since 0.5.
+
+WARNINGS about broken optimizers:
+
+- on the NeXT, "cc -finline-functions" is broken.  gzip produces
+  valid .z files but they are much too large because the string
+  matching code misses most matches. Use "cc -O" instead.
+
+- on the Mips R4000, gcc -O (version 2.3.1) generates bad code, use cc
+  or just gcc -g instead.
+
+- gcc 2.3.3 on the SGI Indigo IRIX 4.0.5 also produces bad code. Use
+  instead: make CC='cc -O2'
+
+- on SparcStation with SunOS 4.1.1 and the SC1.0 compiler, the optimizer
+  works up to -O3 but -O4 does not work.
+
+- MSC 5.1 with -Ox and -DDYN_ALLOC generates bad code in inflate.c.
+  The default is static allocation (no DYN_ALLOC) and -Ox works on inflate.c.
+  But -Ox does not work on util.c, so you must use -Oait -Gs.
+
+For all machines, Use "make check" to check that gzip was compiled correctly.
+
+Please send all comments and bug reports by electronic mail to:
+   Jean-loup Gailly <jloup@chorus.fr>
+
+or, if this fails, to bug-gnu-utils@prep.ai.mit.edu.
+Bug reports should ideally include:
+
+    * The complete output of "gzip -V" (or the contents of revision.h
+      if you can't get gzip to compile)
+    * The hardware and operating system
+    * The compiler used to compile
+    * A description of the bug behavior
+    * The input to gzip, that triggered the bug
+
+The package crypt++.el is highly recommended to manipulate gzip'ed
+file from emacs. It recognizes automatically encrypted and compressed
+files when they are first visited or written. It is available via
+anonymous ftp to roebling.poly.edu [128.238.5.31] in /pub/crypt++.el.
+The same directory contains also patches to dired, ange-ftp, info and
+tar. A patch for tar 1.11.1 is included in the gzip distribution
+because too many people independently reinvent it (see gzip-tar.patch).
+
+The znew and gzexe shell scripts provided with gzip benefit from
+(but do not require) the cpmod utility to transfer file attributes.
+It is available by anonymous ftp on gatekeeper.dec.com in
+/.0/usenet/comp.sources.unix/volume11/cpmod.Z.
+
+gzip is free software, you can redistribute it and/or modify it under
+the terms of the GNU General Public License, a copy of which is
+provided under the name COPYING. The latest version of the gzip
+sources can always be found in prep.ai.mit.edu:/pub/gnu/gzip-*.tar*
+or any of the prep mirror sites. An MSDOS lha self-extracting exe is in
+gzip-msdos-*.exe. The Soloaris 2 executables are in gzip-solaris-*.tar.
+A VMS executable is available in ftp.spc.edu:[.macro32.savesets]gzip-1-*.zip
+(use [.macro32]unzip.exe to extract).
+
+Many thanks to those who provided me with bug reports and feedback.
+See the files THANKS and ChangeLog for more details.
diff --git a/usr/src/contrib/gzip/THANKS b/usr/src/contrib/gzip/THANKS
new file mode 100644 (file)
index 0000000..77a9e3a
--- /dev/null
@@ -0,0 +1,136 @@
+gzip has been written by Jean-loup Gailly <jloup@chorus.fr>, with
+portions written by Mark Adler (inflate.c) and Peter Jannesen
+(unlzw.c). The zip deflate format was defined by Phil Katz.
+Thanks to those who reported problems and suggested
+various improvements.  Here is a partial list of them:
+
+Mark Adler              madler@cco.caltech.edu
+Joseph Arceneaux       jla@gnu.ai.mit.edu
+Tim Auckland            tda10@cus.cam.ac.uk
+Ken-ichiro Aoki         aoki@madonna.physics.ucla.edu
+Eric Backus             ericb@lsid.hp.com
+Becky A. Badgett        badgett@cs.utexas.edu
+Neal Becker             neal@ctd.comsat.com 
+Dieter Becker           becker@med-in.uni-sb.de
+Nelson H. F. Beebe      beebe@geronimo.math.utah.edu
+Jeff Beadles           jeff@onion.rain.com
+Jim Bernard             jbernard@iola.mines.colorado.edu
+Karl Berry              karl@cs.umb.edu
+Wayne E. Bouchard       web@paladine.hacks.arizona.edu
+Marc Boucher            marc@cam.org
+Rodney Brown            rdb@mel.cocam.oz.au
+Bruce                   bde@runx.oz.au
+Leila Burrell-Davis     leilabd@syma.sussex.ac.uk
+Roger Butenuth          butenuth@ira.uka.de
+Bud Carlson             bud@isle.pegasus.com
+Lim Fung Chai           fclim@i1sin.daq.semi.harris.com
+Paul Close              pdc@lunch.wpd.sgi.com
+Kevin Cosgrove          kevinc@tekig6.pen.tek.com
+Stephen J Cowley        s.j.cowley@amtp.cam.ac.uk
+Frank Crawford          frank@photon.ansto.gov.au
+James R. Crawford       qralston@cislabs.pitt.edu
+Lawrence Crowl          crowl@research.cs.orst.edu 
+William E Davidsen      davidsen@ariel.crd.ge.com
+Jeff Deifik             jdeifik@isi.edu
+Vince DeMarco           vince@whatnxt.cuc.ab.ca
+Lawrence R. Dodd        dodd@roebling.poly.edu
+Matthew Donadio         donadio@mxd120.rh.psu.edu
+Andy Dougherty          andy@crystal.phys.lafayette.edu
+John Eaton              jwe@che.utexas.edu
+Paul Eggert             eggert@twinsun.com
+Enami                   enami@sys.ptg.sony.co.jp
+Daniel Eriksson         m91der@bellatrix.tdb.uu.se
+Rik Faith               faith@cs.unc.edu
+Larry Fahnoe            fahnoe@c1mpls.mn.org 
+Per Foreby              perf@efd.lth.se
+Noah Friedman          friedman@gnu.ai.mit.edu
+Bob Friesenhahn         bfriesen@iphase.com
+Andy Fyfe               andy@scp.caltech.edu
+Geoff                   geoff@frs.faxon.com
+Kaveh R. Ghazi          ghazi@staccato.rutgers.edu
+Torbjorn Granlund       tege@sics.se
+Carl Greco              cgreco@parrot.creighton.edu
+Harald Hanche-Olsen     hanche@ams.sunysb.edu
+Ruediger Helsch         ruediger@ramz.ing.tu-bs.de
+Mark C. Henderson       mch@sqwest.wimsey.bc.ca
+Thomas Hiller           hiller@fzi.de
+Eiji Hirai              hirai@cc.swarthmore.edu
+Kjetil Torgrim Homme    kjetilho@ifi.uio.no
+Preston Hunt            gt5708a@prism.gatech.edu
+Shane C Hutchins        sch@nymph.msel.unh.edu
+Lester Ingber          ingber@alumni.caltech.edu
+Ken Ishii               ishii@sni-usa.com
+Per Steinar Iversen     iversen@vsfys1.fi.uib.no
+Denny de Jonge          witaddj@dutrex.tudelft.nl
+Arne H. Juul            arnej@lise.unit.no
+Randy Kirchhof          rkk@posms.aus.tx.us
+Winfried Koenig         win@in.rhein-main.de
+Dana Jacobsen           jacobsd@solar.cor2.epa.gov
+Peter Jannesen         peter@ncs.nl
+Sarantos Kapidakis      sarantos%manteion@ics.forth.gr
+Amir J. Katz            amir@matis.ingr.com
+Ned Kittlitz            kittlitz@seagoon.sw.stratus.com
+Fritz Kleemann          kleemann@informatik.uni-wuerzburg.dbp.de
+Tom Kloos               tk@sequent.com
+Carsten Koch            carsten.koch@icem.de
+Michael D. Lawler       mdlawler@bsu-cs.bsu.edu
+Hugues Leroy            hugues.leroy@irisa.fr 
+Charles Levert          charles@aramis.comm.polymtl.ca
+Torbj|rn Lindh          toobii@elixir.e.kth.se
+David R. Linn          drl@vuse.vanderbilt.edu
+Jamie Lokier            u90jl@ecs.oxford.ac.uk
+David J. MacKenzie     djm@eng.umd.edu
+John R MacMillan        john@chance.gts.org
+Tod McQuillin           mcquill@ccit05.duq.edu
+Bernd Melchers          melchers@chemie.fu-berlin.de
+Jason Merrill           jason@jarthur.claremont.edu
+Dean S. Messing         deanm@medulla.labs.tek.com
+Luke Mewburn            zak@rmit.edu.au
+Jim Meyering           meyering@cs.utexas.edu 
+Chris Moore             moore@src.bae.co.uk
+Helmut Muelner          hmuelner@fiicmds04.tu-graz.ac.at
+Greg Naber              greg@squally.halcyon.com
+Karl L. Noell           noell@informatik.fh-wiesbaden.dbp.de
+Piet van Oostrum        piet@cs.ruu.nl
+Rafael R. Pappalardo    rafapa@obelix.cica.es 
+Hal Peterson            hrp@pecan.cray.com
+Bruno Pillard          bp@chorus.fr
+Franc,ois Pinard        pinard@iro.umontreal.ca
+Thomas Plass            thomas@cogsci.ed.ac.uk
+Mike Polo               mikep@cfsmo.honeywell.com
+Francesco Potorti       pot@fly.cnuce.cnr.it
+Klaus Reimann           kr@cip.physik.uni-stuttgart.de
+Roland B Roberts        roberts@nsrl31.nsrl.rochester.edu
+Kevin Rodgers           kevin@rolling-stone.den.mmc.com
+Kai Uwe Rommel          rommel@informatik.tu-muenchen.de
+Paul A Sand             pas@unh.edu
+Tony Sanders            sanders@bsdi.com
+Mike Sangrey            mike@sojurn.lns.pa.us
+Niimi Satoshi           a01309@cfi.waseda.ac.jp
+Andreas Schwab          schwab@lamothe.informatik.uni-dortmund.de
+Eric Schenk             schenk@cs.toronto.edu
+Rick Sladkey            jrs@world.std.com
+Daniel L Smith          dls@autodesk.com
+Paul Southworth         pauls@css.itd.umich.edu
+Rob Spencer             robbie@winkle.bhpese.oz.au
+Richard Stallman       rms@gnu.ai.mit.edu
+Carsten Steger          carsten.steger@informatik.tu-muenchen.de
+Ed Sznyter              ews@babel.babel.com
+Andrew Telford          ajt@peregrin.resmel.bhp.com.au
+Glenn E. Thobe          thobe@getunx.info.com
+Kei Thomsen             kt@keihh.hanse.de
+Karsten Thygesen        karthy@dannug.dk
+Stephane Tsacas         slt@is21.isoft.fr
+Stephen Tweedie         sct@dcs.ed.ac.uk
+Sotiris Vassilopoulos   vassilopoulos@virginia.edu
+Pedro A. M. Vazquez     vazquez@iqm.unicamp.br
+Arjan de Vet            devet@win.tue.nl
+Vadim V. Vlasov         vvlasov@inucres.msk.su
+Eduard Vopicka          eduard.vopicka@vse.cs 
+Theo Vosse              vosse@ruls41.leidenuniv.nl
+Marcel Waldvogel        marcel@nice.usergroup.ethz.ch
+Gray Watson            gray@antaire.com
+Scott Weikart           scott@igc.apc.org
+Wietze van Winden       wietze@swi.psy.uva.nl
+Bill Wohler             wohler@sap-ag.de
+Christos Zoulas         christos@deshaw.com
diff --git a/usr/src/contrib/gzip/TODO b/usr/src/contrib/gzip/TODO
new file mode 100644 (file)
index 0000000..8988781
--- /dev/null
@@ -0,0 +1,58 @@
+TODO file for gzip.
+
+Some of the planned features include:
+
+- Structure the sources so that the compression and decompression code
+  form a library usable by any program, and write both gzip and zip on
+  top of this library. This will be a thread safe library. In the meantime,
+  you can look at the sample program zread.c.
+
+- Make it convenient to define alternative user interfaces (in
+  particular for windowing environments).
+
+- Support in-memory compression for arbitrarily large amounts of data
+  (zip currently supports in-memory compression only for a single buffer.)
+
+- Map files in memory when possible, this is generally much faster
+  than read/write. (zip currently maps entire files at once, this
+  should be done in chunks to reduce memory usage.)
+
+- Add a super-fast compression method, suitable for implementing
+  file systems with transparent compression. One problem is that the
+  best candidate (lzrw1) is patented twice (Waterworth 4,701,745
+  and Gibson & Graybill 5,049,881). The lzrw series of algorithms
+  are available by ftp in ftp.adelaide.edu.au:/pub/compression/lzrw*.
+
+- Add a super-tight (but slow) compression method, suitable for long
+  term archives.  One problem is that the best versions of arithmetic
+  coding are patented (4,286,256 4,295,125 4,463,342 4,467,317
+  4,633,490 4,652,856 4,891,643 4,905,297 4,935,882 4,973,961
+  5,023,611 5,025,258).
+
+  Note: I will introduce new compression methods only if they are
+  significantly better in either speed or compression ratio than the
+  existing method(s). So the total number of different methods should
+  reasonably not exceed 3. (The current 9 compression levels are just
+  tuning parameters for a single method, deflation.)
+
+- Add optional error correction. One problem is that the current version
+  of ecc cannot recover from inserted or missing bytes. It would be
+  nice to recover from the most common error (transfer of a binary
+  file in ascii mode).
+
+- Add a block size (-b) option to improve error recovery in case of
+  failure of a complete sector. Each block could be extracted
+  independently, but this reduces the compression ratio.
+
+- Use a larger window size to deal with some large redundant files that
+  'compress' currently handles better than gzip.
+
+- implement the following options:
+
+   -a    ascii text mode; convert end-of-lines to local OS conventions
+   -e    encrypt
+   -l    list .z file contents
+   
+- support .Z files in SCO 'compress -H' format.
+
+Send comments to Jean-loup Gailly <jloup@chorus.fr>.
diff --git a/usr/src/contrib/gzip/algorithm.doc b/usr/src/contrib/gzip/algorithm.doc
new file mode 100644 (file)
index 0000000..0a5dee8
--- /dev/null
@@ -0,0 +1,148 @@
+1. Algorithm
+
+The deflation algorithm used by zip and gzip is a variation of LZ77
+(Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data.  The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length).  Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes.  (In this
+description, 'string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when zip determines that it
+would be useful to start another block with fresh trees. (This is
+somewhat similar to compress.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (zip -1
+to -9). So zip does not always find the longest possible match but
+generally finds a match which is long enough.
+
+zip also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, zip searches for a
+longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the longer match is emitted afterwards.  Otherwise,
+the original match is kept, and the next match search is attempted only
+N steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, zip reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, zip attempts a complete second search even if
+the first match is already long enough.
+
+
+2. gzip file format
+
+The pkzip format imposes a lot of overhead in various headers, which
+are useful for an archiver but not necessary when only one file is
+compressed. gzip uses a much simpler structure. Numbers are in little
+endian format, and bit 0 is the least significant bit.
+A gzip file is a sequence of compressed members. Each member has the
+following structure:
+
+2 bytes  magic header  0x1f, 0x8b (\037 \213)  
+1 byte   compression method (0..7 reserved, 8 = deflate)
+1 byte   flags
+            bit 0 set: file probably ascii text
+            bit 1 set: continuation of multi-part gzip file
+            bit 2 set: extra field present
+            bit 3 set: original file name present
+            bit 4 set: file comment present
+            bit 5 set: file is encrypted
+            bit 6,7:   reserved
+4 bytes  file modification time in Unix format
+1 byte   extra flags (depend on compression method)
+1 byte   operating system on which compression took place
+
+2 bytes  optional part number (second part=1)
+2 bytes  optional extra field length
+? bytes  optional extra field
+? bytes  optional original file name, zero terminated
+? bytes  optional file comment, zero terminated
+12 bytes optional encryption header
+? bytes  compressed data
+4 bytes  crc32
+4 bytes  uncompressed input size modulo 2^32
+
+The format was designed to allow single pass compression without any
+backwards seek, and without a priori knowledge of the uncompressed
+input size or the available size on the output media. If input does
+not come from a regular disk file, the file modification time is set
+to the time at which compression started.
+
+The time stamp is useful mainly when one gzip file is transferred over
+a network. In this case it would not help to keep ownership
+attributes. In the local case, the ownership attributes are preserved
+by gzip when compressing/decompressing the file. A time stamp of zero
+is ignored.
+
+Bit 0 in the flags is only an optional indication, which can be set by
+a small lookahead in the input data. In case of doubt, the flag is
+cleared indicating binary data. For systems which have different
+file formats for ascii text and binary data, the decompressor can
+use the flag to choose the appropriate format.
+
+It must be possible to detect the end of the compressed data with any
+compression format, regardless of the actual size of the compressed
+data. If the compressed data cannot fit in one file (in particular for
+diskettes), each part starts with a header as described above, but
+only the last part has the crc32 and uncompressed size. A decompressor
+may prompt for additional data for multipart compressed files. It is
+desirable but not mandatory that multiple parts be extractable
+independently so that partial data can be recovered if one of the
+parts is damaged. This is possible only if no compression state is
+kept from one part to the other. The compression-type dependent flags
+can indicate this.
+
+If the file being compressed is on a file system with case insensitive
+names, the original name field must be forced to lower case. There is
+no original file name if the data was compressed from standard input.
+
+On operating systems which support multiple extensions, and on
+original files without extension, the extension ".z" is added to the
+original file name (foo.c => foo.c.z). Otherwise the string "z" (or
+"-z" for VMS) is added to the original extension (foo.c => foo.cz or
+foo.c-z). The original name or extension is truncated if necessary,
+but in this case the original name is always saved in the compressed
+file (foo.doc => foo.doz).
+
+Compression is always performed, even if the compressed file is
+slightly larger than the original. The worst case expansion is
+a few bytes for the gzip file header, plus 5 bytes every 32K block,
+or an expansion ratio of 0.015% for large files.
+
+The encryption is that of zip 1.9. For the encryption check, the
+last byte of the decoded encryption header must be zero. The time
+stamp of an encrypted file might be set to zero to avoid giving a clue
+about the construction of the random header.
+
+Jean-loup Gailly
+jloup@chorus.fr
+
+References:
+
+[LZ77] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+Compression", IEEE Transactions on Information Theory", Vol. 23, No. 3,
+pp. 337-343.
+
+APPNOTE.TXT documentation file in PKZIP 1.93a. It is available by
+ftp in ux1.cso.uiuc.edu:/pc/exec-pc/pkz193a.exe [128.174.5.59]
+Use "unzip pkz193a.exe APPNOTE.TXT" to extract.
diff --git a/usr/src/contrib/gzip/bits.c b/usr/src/contrib/gzip/bits.c
new file mode 100644 (file)
index 0000000..65e78a6
--- /dev/null
@@ -0,0 +1,205 @@
+/* bits.c -- output variable-length bit strings
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+/*
+ *  PURPOSE
+ *
+ *      Output variable-length bit strings. Compression can be done
+ *      to a file or to memory. (The latter is not supported in this version.)
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflate" file format interprets compressed file data
+ *      as a sequence of bits.  Multi-bit strings in the file may cross
+ *      byte boundaries without restriction.
+ *
+ *      The first bit of each byte is the low-order bit.
+ *
+ *      The routines in this file allow a variable-length bit value to
+ *      be output right-to-left (useful for literal values). For
+ *      left-to-right output (useful for code strings from the tree routines),
+ *      the bits must have been reversed first with bi_reverse().
+ *
+ *      For in-memory compression, the compressed bit stream goes directly
+ *      into the requested output buffer. The input data is read in blocks
+ *      by the mem_read() function. The buffer is limited to 64K on 16 bit
+ *      machines.
+ *
+ *  INTERFACE
+ *
+ *      void bi_init (FILE *zipfile)
+ *          Initialize the bit string routines.
+ *
+ *      void send_bits (int value, int length)
+ *          Write out a bit string, taking the source bits right to
+ *          left.
+ *
+ *      int bi_reverse (int value, int length)
+ *          Reverse the bits of a bit string, taking the source bits left to
+ *          right and emitting them right to left.
+ *
+ *      void bi_windup (void)
+ *          Write out any remaining bits in an incomplete byte.
+ *
+ *      void copy_block(char *buf, unsigned len, int header)
+ *          Copy a stored block to the zip file, storing first the length and
+ *          its one's complement if requested.
+ *
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#ifdef DEBUG
+#  include <stdio.h>
+#endif
+
+#ifndef lint
+static char rcsid[] = "$Id: bits.c,v 0.8 1993/02/04 13:21:06 jloup Exp $";
+#endif
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local file_t zfile; /* output gzip file */
+
+local unsigned short bi_buf;
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+local int bi_valid;
+/* Number of valid bits in bi_buf.  All bits above the last valid bit
+ * are always zero.
+ */
+
+int (*read_buf) OF((char *buf, unsigned size)) = file_read;
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+  ulg bits_sent;   /* bit length of the compressed data */
+#endif
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (zipfile)
+    file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
+{
+    zfile  = zipfile;
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = 0L;
+#endif
+
+    /* Set the defaults for file compression. They are set by memcompress
+     * for in-memory compression.
+     */
+    if (zfile != NO_FILE) {
+       read_buf  = file_read;
+    }
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+void send_bits(value, length)
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+#ifdef DEBUG
+    Tracev((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    bits_sent += (ulg)length;
+#endif
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (bi_valid > (int)Buf_size - length) {
+        bi_buf |= (value << bi_valid);
+        put_short(bi_buf);
+        bi_buf = (ush)value >> (Buf_size - bi_valid);
+        bi_valid += length - Buf_size;
+    } else {
+        bi_buf |= value << bi_valid;
+        bi_valid += length;
+    }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+void bi_windup()
+{
+    if (bi_valid > 8) {
+        put_short(bi_buf);
+    } else if (bi_valid > 0) {
+        put_byte(bi_buf);
+    }
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+void copy_block(buf, len, header)
+    char     *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup();              /* align on byte boundary */
+
+    if (header) {
+        put_short((ush)len);   
+        put_short((ush)~len);
+#ifdef DEBUG
+        bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+#ifdef CRYPT
+        int t;
+       if (key) zencode(*buf, t);
+#endif
+       put_byte(*buf++);
+    }
+}
diff --git a/usr/src/contrib/gzip/crypt.c b/usr/src/contrib/gzip/crypt.c
new file mode 100644 (file)
index 0000000..b076380
--- /dev/null
@@ -0,0 +1,6 @@
+/* crypt.c (dummy version) -- do not perform encrytion
+ * Hardly worth copyrighting :-)
+ */
+#ifndef lint
+static char rcsid[] = "$Id: crypt.c,v 0.5 1992/12/21 18:56:56 jloup Exp $";
+#endif
diff --git a/usr/src/contrib/gzip/crypt.h b/usr/src/contrib/gzip/crypt.h
new file mode 100644 (file)
index 0000000..f4aac50
--- /dev/null
@@ -0,0 +1,12 @@
+/* crypt.h (dummy version) -- do not perform encrytion
+ * Hardly worth copyrighting :-)
+ */
+
+#ifdef CRYPT
+#  undef CRYPT      /* dummy version */
+#endif
+
+#define RAND_HEAD_LEN  12  /* length of encryption random header */
+
+#define zencode
+#define zdecode
diff --git a/usr/src/contrib/gzip/deflate.c b/usr/src/contrib/gzip/deflate.c
new file mode 100644 (file)
index 0000000..980a7f3
--- /dev/null
@@ -0,0 +1,733 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Identify new text as repetitions of old text within a fixed-
+ *      length sliding window trailing behind the new text.
+ *
+ *  DISCUSSION
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many info-zippers for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ *  INTERFACE
+ *
+ *      void lm_init (int pack_level, ush *flags)
+ *          Initialize the "longest match" routines for a new file
+ *
+ *      ulg deflate (void)
+ *          Processes a new input file and return its compressed length. Sets
+ *          the compressed length, crc, deflate flags and internal file
+ *          attributes.
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h" /* just for consistency checking */
+
+#include <stdio.h>
+
+#ifndef lint
+static char rcsid[] = "$Id: deflate.c,v 0.12 1993/03/04 19:15:33 jloup Exp $";
+#endif
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+#   define HASH_BITS  13  /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+#   define HASH_BITS  14
+#endif
+#ifndef HASH_BITS
+#   define HASH_BITS  15
+   /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
+ * window with tab_suffix. Check that we can do this:
+ */
+#if WSIZE<<1 > 1<<BITS
+   error: cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+   error: cannot overlay head with tab_prefix1
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK     (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+typedef ush Pos;
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+/* DECLARE(uch, window, 2L*WSIZE); */
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+
+/* DECLARE(Pos, prev, WSIZE); */
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+/* DECLARE(Pos, head, 1<<HASH_BITS); */
+/* Heads of the hash chains or NIL. */
+
+ulg window_size = (ulg)2*WSIZE;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local unsigned ins_h;  /* hash index of string to be inserted */
+
+#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ *   H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int near prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+      unsigned near strstart;      /* start of string to insert */
+      unsigned near match_start;   /* start of matching string */
+local int           eofile;        /* flag set at end of input file */
+local unsigned      lookahead;     /* number of valid bytes ahead in window */
+
+unsigned near max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+local unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value.
+ */
+
+int near good_match;
+/* Use a faster search when the previous match is longer than this */
+
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+typedef struct config {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+} config;
+
+#ifdef  FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+  int near nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0},  /* store only */
+/* 1 */ {4,    4, 16,   16},  /* maximum speed */
+/* 2 */ {6,    8, 16,   16},
+/* 3 */ {8,   16, 32,   32},
+/* 4 */ {8,   16, 64,   64},
+/* 5 */ {8,   16, 128, 128},
+/* 6 */ {8,   32, 128, 256},
+/* 7 */ {8,   64, 128, 512},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the current code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * but these restrictions can easily be removed at a small cost.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ *  Prototypes for local functions.
+ */
+local void fill_window   OF((void));
+      int  longest_match OF((IPos cur_match));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((IPos start, IPos match, int length));
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of s are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+   (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+    prev[(s) & WMASK] = match_head = head[ins_h], \
+    head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+void lm_init (pack_level, flags)
+    int pack_level; /* 0: store, 1: best speed, 9: best compression */
+    ush *flags;     /* general purpose bit flag */
+{
+    register unsigned j;
+
+    if (pack_level < 1 || pack_level > 9) error("bad pack level");
+
+    /* Initialize the hash table. */
+#if defined(MAXSEG_64K) && HASH_BITS == 15
+    for (j = 0;  j < HASH_SIZE; j++) head[j] = NIL;
+#else
+    memzero(head, HASH_SIZE*sizeof(*head));
+#endif
+    /* prev will be initialized on the fly */
+
+    /* Set the default configuration parameters:
+     */
+    max_lazy_match   = configuration_table[pack_level].max_lazy;
+    good_match       = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+    nice_match       = configuration_table[pack_level].nice_length;
+#endif
+    max_chain_length = configuration_table[pack_level].max_chain;
+    if (pack_level == 1) {
+       *flags |= FAST;
+    } else if (pack_level == 9) {
+       *flags |= SLOW;
+    }
+    /* ??? reduce max_chain_length for binary files */
+
+    strstart = 0;
+    block_start = 0L;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+
+#ifdef MAXSEG_64K
+    /* Can't read a 64K block */
+    lookahead = read_buf((char*)window, (unsigned)WSIZE);
+#else
+    lookahead = read_buf((char*)window, 2*WSIZE);
+#endif
+    if (lookahead == 0 || lookahead == (unsigned)EOF) {
+       eofile = 1, lookahead = 0;
+       return;
+    }
+    eofile = 0;
+    /* Make sure that we always have enough lookahead. This is important
+     * if input comes from a device such as a tty.
+     */
+    while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+    ins_h = 0;
+    for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+    /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+     * not important since only literal bytes will be emitted.
+     */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = max_chain_length;   /* max hash chain length */
+    register uch *scan = window + strstart;     /* current string */
+    register uch *match;                        /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = prev_length;                 /* best match length so far */
+    IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+   error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register uch *strend = window + strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ush*)scan;
+    register ush scan_end   = *(ush*)(scan+best_len-1);
+#else
+    register uch *strend = window + strstart + MAX_MATCH;
+    register uch scan_end1  = scan[best_len-1];
+    register uch scan_end   = scan[best_len];
+#endif
+
+    /* Do not waste too much time if we already have a good match: */
+    if (prev_length >= good_match) {
+        chain_length >>= 2;
+    }
+    Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+    do {
+        Assert(cur_match < strstart, "no future");
+        match = window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ush*)(match+best_len-1) != scan_end ||
+            *(ush*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        scan++, match++;
+        do {
+        } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ush*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & WMASK]) > limit
+            && --chain_length != 0);
+
+    return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((char*)window + match,
+                (char*)window + start, length) != EQUAL) {
+        fprintf(stderr,
+            " start %d, match %d, length %d\n",
+            start, match, length);
+        error("invalid match");
+    }
+    if (verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ *    file reads are performed for at least two bytes (required for the
+ *    translate_eol option).
+ */
+local void fill_window()
+{
+    register unsigned n, m;
+    unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+    /* Amount of free space at the end of the window. */
+
+    /* If the window is almost full and there is insufficient lookahead,
+     * move the upper half to the lower one to make room in the upper half.
+     */
+    if (more == (unsigned)EOF) {
+        /* Very unlikely, but possible on 16 bit machine if strstart == 0
+         * and lookahead == 1 (input done one byte at time)
+         */
+        more--;
+    } else if (strstart >= WSIZE+MAX_DIST) {
+        /* By the IN assertion, the window is not empty so we can't confuse
+         * more == 0 with more == 64K on a 16 bit machine.
+         */
+        Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+
+        memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+        match_start -= WSIZE;
+        strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+        block_start -= (long) WSIZE;
+
+        for (n = 0; n < HASH_SIZE; n++) {
+            m = head[n];
+            head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+        }
+        for (n = 0; n < WSIZE; n++) {
+            m = prev[n];
+            prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+            /* If n is not on any hash chain, prev[n] is garbage but
+             * its value will never be used.
+             */
+        }
+        more += WSIZE;
+    }
+    /* At this point, more >= 2 */
+    if (!eofile) {
+        n = read_buf((char*)window+strstart+lookahead, more);
+        if (n == 0 || n == (unsigned)EOF) {
+            eofile = 1;
+        } else {
+            lookahead += n;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+                (char*)NULL, (long)strstart - block_start, (eof))
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length.
+ */
+#ifdef NO_LAZY
+ulg deflate()
+{
+    IPos hash_head; /* head of the hash chain */
+    int flush;      /* set if current block must be flushed */
+    unsigned match_length = 0;  /* length of best match */
+
+    prev_length = MIN_MATCH-1;
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+        }
+        if (match_length >= MIN_MATCH) {
+            check_match(strstart, match_start, match_length);
+
+            flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+            lookahead -= match_length;
+            match_length--; /* string at strstart already in hash table */
+            do {
+                strstart++;
+                INSERT_STRING(strstart, hash_head);
+                /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                 * these bytes are garbage, but it does not matter since the
+                 * next lookahead bytes will always be emitted as literals.
+                 */
+            } while (--match_length != 0);
+        } else {
+            /* No match, output a literal byte */
+            flush = ct_tally (0, window[strstart]);
+            lookahead--;
+        }
+        strstart++; 
+        if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+    }
+    return FLUSH_BLOCK(1); /* eof */
+}
+#else /* LAZY */
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+ulg deflate()
+{
+    IPos hash_head;          /* head of hash chain */
+    IPos prev_match;         /* previous match */
+    int flush;               /* set if current block must be flushed */
+    int match_available = 0; /* set if previous match exists */
+    register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+    extern long isize;        /* byte length of input file, for debug only */
+#endif
+
+    /* Process the input block. */
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        prev_length = match_length, prev_match = match_start;
+        match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && prev_length < max_lazy_match &&
+            strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+
+            /* Ignore a length 3 match if it is too distant: */
+            if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                match_length--;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+
+            check_match(strstart-1, prev_match, prev_length);
+
+            flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted.
+             */
+            lookahead -= prev_length-1;
+            prev_length -= 2;
+            do {
+                strstart++;
+                INSERT_STRING(strstart, hash_head);
+                /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                 * these bytes are garbage, but it does not matter since the
+                 * next lookahead bytes will always be emitted as literals.
+                 */
+            } while (--prev_length != 0);
+            match_available = 0;
+            match_length = MIN_MATCH-1;
+            strstart++;
+            if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        } else if (match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c",window[strstart-1]));
+            if (ct_tally (0, window[strstart-1])) {
+                FLUSH_BLOCK(0), block_start = strstart;
+            }
+            strstart++;
+            lookahead--;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            match_available = 1;
+            strstart++;
+            lookahead--;
+        }
+        Assert (strstart <= isize && lookahead <= isize, "a bit too far");
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+    }
+    if (match_available) ct_tally (0, window[strstart-1]);
+
+    return FLUSH_BLOCK(1); /* eof */
+}
+#endif /* LAZY */
diff --git a/usr/src/contrib/gzip/getopt.c b/usr/src/contrib/gzip/getopt.c
new file mode 100644 (file)
index 0000000..30679b9
--- /dev/null
@@ -0,0 +1,711 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* AIX requires this to be the first thing in the file.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#include <stdio.h>
+
+#if defined(USG) || defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+#include <string.h>
+#endif
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#else  /* Not GNU C library.  */
+#define        __alloca        alloca
+#endif /* GNU C library.  */
+
+#if !__STDC__
+#define const
+#endif
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+#define GETOPT_COMPAT
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+#include <string.h>
+#define        my_index        strchr
+#define        my_bcopy(src, dst, n)   memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (string, chr)
+     char *string;
+     int chr;
+{
+  while (*string)
+    {
+      if (*string == chr)
+       return string;
+      string++;
+    }
+  return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  int i;
+  for (i = 0; i < size; i++)
+    to[i] = from[i];
+}
+#endif                         /* GNU C library.  */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+#ifdef _CRAY
+  char *temp[last_nonopt - first_nonopt];
+#else
+  char **temp = (char **) __alloca (nonopts_size);
+#endif
+
+  /* Interchange the two blocks of data in ARGV.  */
+
+  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+           (optind - last_nonopt) * sizeof (char *));
+  my_bcopy ((char *) temp,
+           (char *) &argv[first_nonopt + optind - last_nonopt],
+           nonopts_size);
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+       {
+         ordering = RETURN_IN_ORDER;
+         ++optstring;
+       }
+      else if (optstring[0] == '+')
+       {
+         ordering = REQUIRE_ORDER;
+         ++optstring;
+       }
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* Special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound = 0;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+         }
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = 0;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                          argv[0], c);
+               c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead. */
+
+int 
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/usr/src/contrib/gzip/getopt.h b/usr/src/contrib/gzip/getopt.h
new file mode 100644 (file)
index 0000000..764f2f4
--- /dev/null
@@ -0,0 +1,128 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if    __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+enum _argtype
+{
+  no_argument,
+  required_argument,
+  optional_argument
+};
+
+#if __STDC__ || defined(PROTO)
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/usr/src/contrib/gzip/gzexe b/usr/src/contrib/gzip/gzexe
new file mode 100644 (file)
index 0000000..bac5aae
--- /dev/null
@@ -0,0 +1,134 @@
+#!/bin/sh
+# gzexe: compressor for Unix executables.
+# Use this only for binaries that you do not use frequently.
+#
+# The compressed version is a shell script which decompresses itself after
+# skipping $skip lines of shell commands.  We try invoking the compressed
+# executable with the original name (for programs looking at their name).
+# We also try to retain the original file permissions on the compressed file.
+# For safety reasons, gzexe will not create setuid or setgid shell scripts.
+
+# Warning: the first line of this file must be either : or #!/bin/sh
+# The : is required for some old versions of csh.
+
+x=`basename $0`
+if test $# = 0; then
+  echo compress executables. original file foo is renamed to foo~
+  echo usage: ${x} [-d] files...
+  echo   "   -d  decompress the executables"
+  exit 1
+fi
+
+tmp=gz$$
+trap "rm -f $tmp; exit 1" 1 2 3 5 10 13 15
+
+decomp=0
+res=0
+test "$x" = "ungzexe" && decomp=1
+if test "$1" = "-d"; then
+  decomp=1
+  shift
+fi
+
+echo hi > zfoo1$$
+echo hi > zfoo2$$
+if test -z "`(${CPMOD-cpmod} zfoo1$$ zfoo2$$) 2>&1`"; then
+  cpmod=${CPMOD-cpmod}
+fi
+rm -f zfoo[12]$$
+
+for i do
+  if test ! -f "$i" ; then
+    echo ${x}: $i not a file
+    res=1
+    continue
+  fi
+  if test $decomp -eq 0; then
+    if sed -e 1d -e 2q "$i" | grep "^skip=[0-9]*$" >/dev/null; then
+      echo "${x}: $i is already gzexe'd"
+      continue
+    fi
+  fi
+  if ls -l "$i" | grep '^...[sS]' > /dev/null; then
+    echo "${x}: $i has setuid permission, unchanged"
+    continue
+  fi
+  if ls -l "$i" | grep '^......[sS]' > /dev/null; then
+    echo "${x}: $i has setgid permission, unchanged"
+    continue
+  fi
+  if test "`basename $i`" = gzip; then
+    echo "${x}: cannot compress gzip itself"
+    continue
+  fi
+  if test -z "$cpmod"; then
+    cp -p "$i" $tmp 2>/dev/null || cp "$i" $tmp
+    if test -w $tmp 2>/dev/null; then
+      writable=1
+    else
+      writable=0
+      chmod u+w $tmp 2>/dev/null
+    fi
+  fi
+  if test $decomp -eq 0; then
+    sed 1q $0 > $tmp
+    cat >> $tmp <<'EOF'
+skip=18
+if tail +$skip $0 | gzip -cd > /tmp/gztmp$$; then
+  chmod 755 /tmp/gztmp$$
+  prog="`basename $0`"
+  if ln /tmp/gztmp$$ "/tmp/$prog" 2>/dev/null; then
+    trap '/bin/rm -f /tmp/gztmp$$ "/tmp/$prog"; exit $res' 0
+    (sleep 5; /bin/rm -f /tmp/gztmp$$ "/tmp/$prog") 2>/dev/null &
+    /tmp/"$prog" ${1+"$@"}; res=$?
+  else
+    trap '/bin/rm -f /tmp/gztmp$$; exit $res' 0
+    (sleep 5; /bin/rm -f /tmp/gztmp$$) 2>/dev/null &
+    /tmp/gztmp$$ ${1+"$@"}; res=$?
+  fi
+else
+  echo Cannot decompress $0; exit 1
+fi; exit $res
+EOF
+    gzip -cv9 "$i" >> $tmp || {
+      /bin/rm -f $tmp
+      echo ${x}: compression not possible for $i, file unchanged.
+      res=1
+      continue
+    }
+
+  else
+    # decompression
+    skip=18
+    if sed -e 1d -e 2q "$i" | grep "^skip=[0-9]*$" >/dev/null; then
+      eval `sed -e 1d -e 2q "$i"`
+    fi
+    if tail +$skip "$i" | gzip -cd > $tmp; then
+      :
+    else
+      echo ${x}: $i probably not in gzexe format, file unchanged.
+      res=1
+      continue
+    fi
+  fi
+  rm -f "$i~"
+  mv "$i" "$i~" || {
+    echo ${x}: cannot backup $i as $i~
+    rm -f $tmp
+    res=1
+    continue
+  }
+  mv $tmp "$i" || cp -p $tmp "$i" 2>/dev/null || cp $tmp "$i" || {
+    echo ${x}: cannot create $i
+    rm -f $tmp
+    res=1
+    continue
+  }
+  rm -f $tmp
+  if test -n "$cpmod"; then
+    $cpmod "$i~" "$i" 2>/dev/null
+  elif test $writable -eq 0; then
+    chmod u-w $i 2>/dev/null
+  fi
+done
+exit $res
diff --git a/usr/src/contrib/gzip/gzexe.1 b/usr/src/contrib/gzip/gzexe.1
new file mode 100644 (file)
index 0000000..68e4127
--- /dev/null
@@ -0,0 +1,36 @@
+.TH GZEXE 1
+.SH NAME
+gzexe \- compress executable files in place
+.SH SYNOPSIS
+.B gzexe
+[ name ...  ]
+.SH DESCRIPTION
+The
+.I  gzexe
+utility allows you to compress executables in place and have them
+automatically uncompress and execute when you run them (at a penalty
+in performance).  For example if you execute ``gzexe /bin/cat'' it
+will create the following two files:
+.nf
+.br
+    -r-xr-xr-x  1 root  bin   9644 Feb 11 11:16 /bin/cat
+    -r-xr-xr-x  1 bin   bin  24576 Nov 23 13:21 /bin/cat~
+.fi
+/bin/cat~ is the original file and /bin/cat is the self-uncompressing
+executable file.  You can remove /bin/cat~ once you are sure that
+/bin/cat works properly.
+.PP
+This utility is most useful on systems with very small disks.
+.SH OPTIONS
+.TP
+.B \-d
+Decompress the given executables instead of compressing them.
+.SH "SEE ALSO"
+gzip(1), znew(1), zmore(1), zcmp(1), zforce(1)
+.SH "BUGS"
+.I gzexe 
+attempts to retain the original file attributes on the compressed executable,
+but you may have to fix them manually in some cases, using
+.I chmod
+or
+.I chown.
diff --git a/usr/src/contrib/gzip/gzip.1 b/usr/src/contrib/gzip/gzip.1
new file mode 100644 (file)
index 0000000..1518f5e
--- /dev/null
@@ -0,0 +1,340 @@
+.PU
+.TH GZIP 1 local
+.SH NAME
+gzip, gunzip, zcat \- compress or expand files
+.SH SYNOPSIS
+.ll +8
+.B gzip
+.RB [ " \-cdfhLrtvV19 " ]
+[
+.I "name \&..."
+]
+.ll -8
+.br
+.B gunzip
+.RB [ " \-cfhLrtvV " ]
+[
+.I "name \&..."
+]
+.br
+.B zcat
+.RB [ " \-hLV " ]
+[
+.I "name \&..."
+]
+.SH DESCRIPTION
+.I Gzip
+reduces the size of the named files using Lempel-Ziv coding (LZ77).
+Whenever possible,
+each file is replaced by one with the extension
+.B "\&.z,"
+while keeping the same ownership modes, access and modification times.
+(The extension is
+.B "\-z"
+for VMS,
+.B "z"
+for MSDOS, OS/2 and Atari.)
+If no files are specified, the standard input is compressed to the
+standard output. If the new file name is too long,
+.I gzip
+truncates it and keeps the original file name in the compressed file.
+.I Gzip
+will only attempt to compress regular files.
+In particular, it will ignore symbolic links.
+.PP
+Compressed files can be restored to their original form using
+.I gzip -d
+or
+.I gunzip
+or
+.I zcat.
+.PP
+.I gunzip
+takes a list of files on its command line and replaces each
+file whose name ends with
+.B "\&.z"
+or
+.B "\&.Z"
+or
+.B "\&-z"
+and which begins with the correct magic number with an uncompressed
+file without the original extension.
+.I gunzip
+also recognizes the special extensions
+.B "\&.tgz"
+and
+.B "\&.taz"
+as shorthands for
+.B "\&.tar.z"
+or
+.B "\&.tar.Z"
+.PP
+.I gunzip
+can currently decompress files created by
+.I gzip, zip, compress
+or
+.I pack.
+The detection of the input format is automatic.  When using
+the first two formats,
+.I gunzip
+checks a 32 bit CRC. For
+.I pack, gunzip
+checks the uncompressed length. The
+.I compress
+format was not designed to allow consistency checks. However
+.I gunzip
+is sometimes able to detect a bad .Z file. If you get an error
+when uncompressing a .Z file, do not assume that the .Z file is
+correct simply because the standard
+.I uncompress
+does not complain. This generally means that the standard
+.I uncompress
+does not check its input, and happily generates garbage output.
+.PP
+Files created by
+.I zip
+can be uncompressed by gzip only if they have a single member compressed
+with the 'deflation' method. This feature is only intended to help
+conversion of tar.zip files to the tar.z format. To extract zip files
+with several members, use
+.I unzip
+instead of
+.I gunzip.
+.PP
+.I zcat
+is identical to
+.I gunzip
+.B \-c.
+(On some systems,
+.I zcat
+may be installed as
+.I gzcat
+to preserve the original link to
+.I compress.)
+.I zcat
+uncompresses either a list of files on the command line or its
+standard input and writes the uncompressed data on standard output.
+.I zcat
+will uncompress files that have the correct magic number whether
+they have a
+.B "\&.z"
+suffix or not.
+.PP
+.I Gzip
+uses the Lempel-Ziv algorithm used in
+.I zip
+and PKZIP.
+The amount of compression obtained depends on the size of the
+input and the distribution of common substrings.
+Typically, text such as source code or English
+is reduced by 60\-70%.
+Compression is generally much better than that achieved by
+LZW (as used in 
+.IR compress ),
+Huffman coding (as used in
+.IR pack ),
+or adaptive Huffman coding
+.RI ( compact ).
+.PP
+Compression is always performed, even if the compressed file is
+slightly larger than the original. The worst case expansion is
+a few bytes for the gzip file header, plus 5 bytes every 32K block,
+or an expansion ratio of 0.015% for large files.
+.I gzip
+preserves the mode, ownership and timestamps of files when compressing
+or decompressing.
+
+.SH OPTIONS
+.TP
+.B \-c --stdout
+Write output on standard output; keep original files unchanged.
+If there are several input files, the output consists of a sequence of
+independently compressed members. To obtain better compression,
+concatenate all input files before compressing them.
+.TP
+.B \-d --decompress
+Decompress.
+.TP
+.B \-f --force
+Force compression or decompression even if the file has multiple links
+or the corresponding file already exists.
+If
+.B \-f
+is not given,
+and when not running in the background,
+.I gzip
+prompts to verify whether an existing file should be overwritten.
+.TP
+.B \-h --help
+Display a help screen.
+.TP
+.B \-L --license
+Display the
+.I gzip
+license.
+.TP
+.B \-q --quiet
+Suppress all warnings.
+.TP
+.B \-r --recurse
+Travel the directory structure recursively. If any of the file names
+specified on the command line are directories, 
+.I gzip
+will descend into the directory and compress all the files it finds there
+(or decompress them in the case of
+.I gunzip
+).
+.TP
+.B \-t --test
+Test. Check the compressed file integrity.
+.TP
+.B \-v --verbose
+Verbose. Display the name and percentage reduction for each file compressed.
+.TP
+.B \-V --version
+Version. Display the version number and compilation options.
+.TP
+.B \-# --fast --best
+Regulate the speed of compression using the specified digit
+.IR # ,
+where
+.B \-1
+or
+.B \-\-fast
+indicates the fastest compression method (less compression)
+and
+.B \-9
+or
+.B \-\-best
+indicates the slowest compression method (optimal compression).
+The default compression level is
+.BR \-5.
+.SH "ADVANCED USAGE"
+Multiple compressed files can be concatenated. In this case,
+.I gunzip
+will extract all members at once. For example:
+
+      gzip -c file1  > foo.z
+      gzip -c file2 >> foo.z
+Then
+      gunzip -c foo
+
+is equivalent to
+
+      cat file1 file2
+
+In case of damage to one member of a .z file, other members can
+still be recovered (if the damaged member is removed). However,
+you can get better compression by compressing all members at once:
+
+      cat file1 file2 | gzip > foo.z
+
+compresses better than
+
+      gzip -c file1 file2 > foo.z
+
+If you want to recompress concatenated files to get better compression, do:
+
+      zcat old.z | gzip > new.z
+.SH "ENVIRONMENT"
+The environment variable
+.B GZIP
+can hold a set of default options for
+.I gzip.
+These options are interpreted first and can be overwritten by
+explicit command line parameters. For example:
+      for sh:    GZIP="-8 -v"; export GZIP
+      for csh:   setenv GZIP "-8 -v"
+      for MSDOS: set GZIP=-8 -v
+
+On Vax/VMS, the name of the environment variable is GZIP_OPT, to
+avoid a conflict with the symbol set for invocation of the program.
+.SH "SEE ALSO"
+znew(1), zcmp(1), zmore(1), zforce(1), gzexe(1), zip(1), unzip(1), compress(1),
+pack(1), compact(1)
+.SH "DIAGNOSTICS"
+Exit status is normally 0;
+if an error occurs, exit status is 1. If a warning occurs, exit status is 2.
+.PP
+Usage: gzip [-cdfhLrtvV19] [file ...]
+.in +8
+Invalid options were specified on the command line.
+.in -8
+.IR file :
+not in gzip format
+.in +8
+The file specified to
+.I gunzip
+has not been compressed.
+.in -8
+.IR file:
+Corrupt input. Use zcat to recover some data.
+.in +8
+The compressed file has been damaged. The data up to the point of failure
+can be recovered using
+.in +8
+zcat file > recover
+.in -16
+.IR file :
+compressed with 
+.I xx
+bits, can only handle 
+.I yy
+bits
+.in +8
+.I File
+was compressed (using LZW) by a program that could deal with
+more 
+.I bits
+than the decompress code on this machine.
+Recompress the file with gzip, which compresses better and uses
+less memory.
+.in -8
+.IR file :
+already has z suffix -- no change
+.in +8
+The file is assumed to be already compressed.
+Rename the file and try again or use zcat.
+.in -8
+.I file
+already exists; do you wish to overwrite (y or n)?
+.in +8
+Respond "y" if you want the output file to be replaced; "n" if not.
+.in -8
+gunzip: corrupt input
+.in +8
+A SIGSEGV violation was detected which usually means that the input file has
+been corrupted.
+.in -8
+.I "xx.x%"
+.in +8
+Percentage of the input saved by compression.
+(Relevant only for
+.BR \-v \.)
+.in -8
+-- not a regular file or directory: ignored
+.in +8
+When the input file is not a regular file or directory,
+(e.g. a symbolic link, socket, FIFO, device file), it is
+left unaltered.
+.in -8
+-- has 
+.I xx 
+other links: unchanged
+.in +8
+The input file has links; it is left unchanged.  See
+.IR ln "(1)"
+for more information. Use the
+.B \-f
+flag to force compression of multiply-linked files.
+.in -8
+.SH CAVEATS
+The .z extension is already used by
+.IR pack "(1)".
+You can link
+.I gzip
+to
+.I pcat
+to get transparent decompression for programs expecting .z files to be in
+.IR pack
+format.
diff --git a/usr/src/contrib/gzip/gzip.c b/usr/src/contrib/gzip/gzip.c
new file mode 100644 (file)
index 0000000..c81f478
--- /dev/null
@@ -0,0 +1,1369 @@
+/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+static char  *license_msg[] = {
+"   Copyright (C) 1992-1993 Jean-loup Gailly",
+"   This program is free software; you can redistribute it and/or modify",
+"   it under the terms of the GNU General Public License as published by",
+"   the Free Software Foundation; either version 2, or (at your option)",
+"   any later version.",
+"",
+"   This program is distributed in the hope that it will be useful,",
+"   but WITHOUT ANY WARRANTY; without even the implied warranty of",
+"   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
+"   GNU General Public License for more details.",
+"",
+"   You should have received a copy of the GNU General Public License",
+"   along with this program; if not, write to the Free Software",
+"   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+0};
+
+/* Compress files with zip algorithm and 'compress' interface.
+ * See usage() and help() functions below for all options.
+ * Outputs:
+ *        file.z:   compressed file with same mode, owner, and utimes
+ *        file.Z:   same with -Z option (old compress format)
+ *     or stdout with -c option or if stdin used as input.
+ * If the OS does not support file names with multiple dots (MSDOS, VMS) or
+ * if the output file name had to be truncated, the original name is kept
+ * in the compressed .z file. (Feature not available in old compress format.)
+ * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-z.
+ *
+ * For the meaning of all compilation flags, see comments in Makefile.in.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: gzip.c,v 0.17 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h"
+#include "revision.h"
+#include "getopt.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+               /* configuration */
+
+#ifndef NO_FCNTL_H
+#  include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+#  include <stdlib.h>
+#else
+   extern int errno;
+#endif
+
+#if defined(DIRENT) || defined(_POSIX_VERSION)
+#  include <dirent.h>
+   typedef struct dirent dir_type;
+#  define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
+#  define DIR_OPT "DIRENT"
+#else
+#  define NLENGTH(dirent) ((dirent)->d_namlen)
+#  ifdef SYSDIR
+#    include <sys/dir.h>
+     typedef struct direct dir_type;
+#    define DIR_OPT "SYSDIR"
+#  else
+#    ifdef SYSNDIR
+#      include <sys/ndir.h>
+       typedef struct direct dir_type;
+#      define DIR_OPT "SYSNDIR"
+#    else
+#      ifdef NDIR
+#        include <ndir.h>
+         typedef struct direct dir_type;
+#        define DIR_OPT "NDIR"
+#      else
+#        define NO_DIR
+#        define DIR_OPT "NO_DIR"
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifndef NO_UTIME
+#  ifndef NO_UTIME_H
+#    include <utime.h>
+#    define TIME_OPT "UTIME"
+#  else
+#    ifdef HAVE_SYS_UTIME_H
+#      include <sys/utime.h>
+#      define TIME_OPT "SYS_UTIME"
+#    else
+       struct utimbuf {
+         time_t actime;
+         time_t modtime;
+       };
+#      define TIME_OPT ""
+#    endif
+#  endif
+#else
+#  define TIME_OPT "NO_UTIME"
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+typedef RETSIGTYPE (*sig_type)();
+
+#ifndef        O_BINARY
+#  define  O_BINARY  0  /* creation mode for open() */
+#endif
+
+#ifndef O_CREAT
+   /* Pure BSD system? */
+#  include <sys/file.h>
+#  ifndef O_CREAT
+#    define O_CREAT FCREAT
+#  endif
+#  ifndef O_EXCL
+#    define O_EXCL FEXCL
+#  endif
+#endif
+
+#define RW_USER 0600    /* creation mode for open() */
+
+#ifndef MAX_PATH_LEN
+#  define MAX_PATH_LEN   1024 /* max pathname length */
+#endif
+
+#define MAX_HEADER_LEN   16
+/* max length of a compressed file header, fixed part only */
+
+               /* global buffers */
+
+DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(ush, d_buf,  DIST_BUFSIZE);
+DECLARE(uch, window, 2L*WSIZE);
+#ifndef MAXSEG_64K
+    DECLARE(ush, tab_prefix, 1L<<BITS);
+#else
+    DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
+    DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
+#endif
+
+               /* local variables */
+
+int to_stdout = 0;    /* output to stdout (-c) */
+int decompress = 0;   /* decompress (-d) */
+int force = 0;        /* don't ask questions, compress links (-f) */
+int recursive = 0;    /* recurse through directories (-r) */
+int verbose = 0;      /* be verbose (-v) */
+int quiet = 0;        /* be very quiet (-q) */
+int quit_on_tty = 0;  /* quit if compressing to or decompressing from a tty */
+int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
+int test = 0;         /* test .z file integrity */
+int foreground;       /* set if program run in foreground */
+char *progname;       /* program name */
+int maxbits = BITS;   /* max bits per code for LZW */
+int method = DEFLATED;/* compression method */
+int level = 5;        /* compression level */
+int exit_code = OK;   /* program exit code */
+int save_orig_name;   /* set if original name must be saved */
+int last_member;      /* set for .zip and .Z files */
+int part_nb;          /* number of parts in .z file */
+ulg time_stamp;       /* original time stamp (modification time) */
+long ifile_size;      /* input file size, -1 for devices (debug only) */
+char *env;            /* contents of GZIP env variable */
+char **args = NULL;   /* argv pointer if GZIP env variable defined */
+
+long bytes_in;             /* number of input bytes */
+long bytes_out;            /* number of output bytes */
+char ifname[MAX_PATH_LEN]; /* input filename */
+char ofname[MAX_PATH_LEN]; /* output filename */
+int  remove_ofname = 0;           /* remove output file on error */
+struct stat istat;         /* status for input file */
+int  ifd;                  /* input file descriptor */
+int  ofd;                  /* output file descriptor */
+unsigned insize;           /* valid bytes in inbuf */
+unsigned inptr;            /* index of next byte to be processed in inbuf */
+unsigned outcnt;           /* bytes in output buffer */
+
+struct option longopts[] =
+{
+ /* { name  has_arg  *flag  val } */
+ /* {"ascii",      0, 0, 'a'},  ascii text mode */
+    {"stdout",     0, 0, 'c'}, /* write output on standard output */
+    {"decompress", 0, 0, 'd'}, /* decompress */
+    {"uncompress", 0, 0, 'd'}, /* decompress */
+ /* {"encrypt",    0, 0, 'e'},    encrypt */
+    {"force",      0, 0, 'f'}, /* force overwrite of output file */
+    {"help",       0, 0, 'h'}, /* give help */
+ /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
+ /* {"list",       0, 0, 'l'},    list .z file contents */
+    {"license",    0, 0, 'L'}, /* display software license */
+    {"quiet",      0, 0, 'q'}, /* quiet mode */
+    {"recurse",    0, 0, 'r'}, /* recurse through directories */
+    {"test",       0, 0, 't'}, /* test compressed file integrity */
+    {"verbose",    0, 0, 'v'}, /* verbose mode */
+    {"version",    0, 0, 'V'}, /* display version number */
+    {"fast",       0, 0, '1'}, /* compress faster */
+    {"best",       0, 0, '9'}, /* compress better */
+    {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
+    {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
+    { 0, 0, 0, 0 }
+};
+
+/* local functions */
+
+local void usage        OF((void));
+local void help         OF((void));
+local void license      OF((void));
+local void version      OF((void));
+local void treat_stdin  OF((void));
+local void treat_file   OF((char *iname));
+local int create_outfile OF((void));
+local int  do_stat      OF((char *name, struct stat *sbuf));
+local char *get_suffix  OF((char *name));
+local int  get_istat    OF((char *iname, struct stat *sbuf));
+local int  make_ofname  OF((void));
+local int  same_file    OF((struct stat *stat1, struct stat *stat2));
+local int name_too_long OF((char *name, struct stat *statb));
+local int  get_method   OF((int in));
+local int  check_ofname OF((void));
+local void reset_times  OF((char *name, struct stat *statb));
+local void copy_stat    OF((struct stat *ifstat));
+local void treat_dir    OF((char *dir));
+local void do_exit      OF((int exitcode));
+      int main          OF((int argc, char **argv));
+
+void (*work) OF((int infile, int outfile)) = zip; /* function to call */
+
+#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
+
+/* ======================================================================== */
+local void usage()
+{
+    fprintf(stderr,
+#ifdef LZW
+#  ifdef NO_DIR
+            "usage: %s [-cdfhLtvVZ19] [-b maxbits] [file ...]\n",
+#  else
+            "usage: %s [-cdfhLrtvVZ19] [-b maxbits] [file ...]\n",
+#  endif
+#else /* !LZW */
+#  ifdef NO_DIR
+            "usage: %s [-cdfhLtvV19] [file ...]\n",
+#  else
+            "usage: %s [-cdfhLrtvV19] [file ...]\n",
+#  endif
+#endif /* LZW */
+             progname);
+}
+/* ======================================================================== */
+local void help()
+{
+    static char  *help_msg[] = {
+/* -a --ascii       ascii text; convert end-of-lines to local OS conventions */
+ " -c --stdout      write on standard output, keep original files unchanged",
+ " -d --decompress  decompress",
+/* -e --encrypt     encrypt */
+ " -f --force       force overwrite of output file and compress links",
+ " -h --help        give this help",
+/* -k --pkzip       force output in pkzip format */
+/* -l --list        list .z file contents */
+ " -L --license     display software license",
+ " -q --quiet       suppress all warnings",
+#ifndef NO_DIR
+ " -r --recurse     recurse through directories",
+#endif
+ " -t --test        test compressed file integrity",
+ " -v --verbose     verbose mode",
+ " -V --version     display version number",
+ " -1 --fast        compress faster",
+ " -9 --best        compress better",
+#ifdef LZW
+ " -Z --lzw         produce output compatible with old compress",
+ " -b --bits maxbits   max number of bits per code (implies -Z)",
+#endif
+ " file...          files to (de)compress. If none given, use standard input.",
+  0};
+    char **p = help_msg;
+
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+    usage();
+    while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void license()
+{
+    char **p = license_msg;
+
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+    while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void version()
+{
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+
+    fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
+#ifdef STDC_HEADERS
+    fprintf(stderr, "STDC_HEADERS ");
+#endif
+#ifdef HAVE_UNISTD_H
+    fprintf(stderr, "HAVE_UNISTD_H ");
+#endif
+#ifdef NO_MEMORY_H
+    fprintf(stderr, "NO_MEMORY_H ");
+#endif
+#ifdef NO_STRING_H
+    fprintf(stderr, "NO_STRING_H ");
+#endif
+#ifdef NO_SYMLINK
+    fprintf(stderr, "NO_SYMLINK ");
+#endif
+#ifdef NO_MULTIPLE_DOTS
+    fprintf(stderr, "NO_MULTIPLE_DOTS ");
+#endif
+#ifdef NO_CHOWN
+    fprintf(stderr, "NO_CHOWN ");
+#endif
+#ifdef PROTO
+    fprintf(stderr, "PROTO ");
+#endif
+#ifdef ASMV
+    fprintf(stderr, "ASMV ");
+#endif
+#ifdef DEBUG
+    fprintf(stderr, "DEBUG ");
+#endif
+#ifdef DYN_ALLOC
+    fprintf(stderr, "DYN_ALLOC ");
+#endif
+#ifdef MAXSEG_64K
+    fprintf(stderr, "MAXSEG_64K");
+#endif
+    fprintf(stderr, "\n");
+}
+
+/* ======================================================================== */
+int main (argc, argv)
+    int argc;
+    char **argv;
+{
+    int file_count = 0; /* number of files to precess */
+    int proglen;        /* length of progname */
+    int optc;           /* current option */
+
+    EXPAND(argc, argv); /* wild card expansion if necessary */
+
+    progname = basename(argv[0]);
+    proglen = strlen(progname);
+
+    /* Suppress .exe for MSDOS, OS/2 and VMS: */
+    if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
+        progname[proglen-4] = '\0';
+    }
+
+    /* Add options in GZIP environment variable if there is one */
+    env = add_envopt(&argc, &argv, OPTIONS_VAR);
+    if (env != NULL) args = argv;
+
+    foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
+    if (foreground) {
+       signal (SIGINT, (sig_type)abort_gzip);
+    }
+#ifdef SIGTERM
+    signal(SIGTERM, (sig_type)abort_gzip);
+#endif
+#ifdef SIGHUP
+    signal(SIGHUP,  (sig_type)abort_gzip);
+#endif
+
+#ifndef GNU_STANDARD
+    /* For compatibility with old compress, use program name as an option.
+     * If you compile with -DGNU_STANDARD, this program will behave as
+     * gzip even if it is invoked under the name gunzip or zcat.
+     *
+     * Systems which do not support links can still use -d or -dc.
+     * Ignore an .exe extension for MSDOS, OS/2 and VMS.
+     */
+    if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
+       || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
+       decompress = 1;
+    } else if (strequ(progname+1, "cat")       /* zcat, pcat */
+           || strequ(progname, "gzcat")) {    /* gzcat */
+       decompress = to_stdout = 1;
+    }
+#endif
+
+    while ((optc = getopt_long (argc, argv, "b:cdfhLqrtvVZ123456789",
+                               longopts, (int *)0)) != EOF) {
+       switch (optc) {
+       case 'b':
+           maxbits = atoi(optarg);
+           break;
+       case 'c':
+           to_stdout = 1; break;
+       case 'd':
+           decompress = 1; break;
+       case 'f':
+           force++; break;
+       case 'h':
+           help(); do_exit(OK); break;
+       case 'L':
+           license(); do_exit(OK); break;
+       case 'q':
+           quiet = 1; verbose = 0; break;
+       case 'r':
+#ifdef NO_DIR
+           fprintf(stderr, "%s: -r not supported on this system\n", progname);
+           usage();
+           do_exit(ERROR); break;
+#else
+           recursive = 1; break;
+#endif
+       case 't':
+           test = decompress = to_stdout = 1;
+           break;
+       case 'v':
+           verbose++; quiet = 0; break;
+       case 'V':
+           version(); quit_on_tty = 1; break;
+       case 'Z':
+#ifdef LZW
+           do_lzw = 1; break;
+#else
+           fprintf(stderr, "%s: -Z not supported in this version\n",
+                   progname);
+           usage();
+           do_exit(ERROR); break;
+#endif
+       case '1':  case '2':  case '3':  case '4':
+       case '5':  case '6':  case '7':  case '8':  case '9':
+           level = optc - '0';
+           break;
+       default:
+           /* Error message already emitted by getopt_long. */
+           usage();
+           do_exit(ERROR);
+       }
+    } /* loop on all arguments */
+
+    file_count = argc - optind;
+
+    if (do_lzw && !decompress) work = lzw;
+
+    /* Allocate all global buffers (for DYN_ALLOC option) */
+    ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
+    ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+    ALLOC(ush, d_buf,  DIST_BUFSIZE);
+    ALLOC(uch, window, 2L*WSIZE);
+#ifndef MAXSEG_64K
+    ALLOC(ush, tab_prefix, 1L<<BITS);
+#else
+    ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
+    ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
+#endif
+
+    /* And get to work */
+    if (file_count != 0) {
+       if (to_stdout && !test) {
+           SET_BINARY_MODE(fileno(stdout));
+       }
+        while (optind < argc) {
+           treat_file(argv[optind++]);
+       }
+    } else {  /* Standard input */
+       treat_stdin();
+    }
+    do_exit(exit_code);
+    return exit_code; /* just to avoid lint warning */
+}
+
+/* ========================================================================
+ * Compress or decompress stdin
+ */
+local void treat_stdin()
+{
+    if (isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
+       /* Do not send compressed data to the terminal or read it from
+        * the terminal. We get here when user invoked the program
+        * without parameters, so be helpful. However, on systems supporting
+         * pseudo ttys, let the beginner stare at the 'hung' program
+        * (explicity request from Noah Friedman). Don't give an error message
+        * if the user only wanted the version number (gzip -V).
+        */
+       if (quit_on_tty) do_exit(OK);
+#ifdef NO_PTY
+       fprintf(stderr,
+         "%s: compressed data not %s a terminal. Redirect %s file or pipe.\n",
+               progname, decompress ? "read from" : "written to",
+               decompress ? "from" : "to");
+       fprintf(stderr,"For help, type: %s -h\n", progname);
+       do_exit(ERROR);
+#endif
+    }
+
+    SET_BINARY_MODE(fileno(stdin));
+    if (!test) SET_BINARY_MODE(fileno(stdout));
+
+    strcpy(ifname, "stdin");
+    strcpy(ofname, "stdout");
+
+    /* Get the time stamp on the input file */
+#ifdef NO_STDIN_FSTAT
+    time_stamp = 0; /* time unknown */
+#else
+    if (fstat(fileno(stdin), &istat) != 0) {
+       error("fstat(stdin)");
+    } 
+    time_stamp = istat.st_mtime;
+#endif
+    ifile_size = -1L; /* convention for unknown size */
+
+    clear_bufs(); /* clear input and output buffers */
+    to_stdout = 1;
+    part_nb = 0;
+
+    if (decompress) {
+       method = get_method(ifd);
+       if (method < 0) {
+           do_exit(exit_code); /* error message already emitted */
+       }
+    }
+
+    /* Actually do the compression/decompression. Loop over zipped members.
+     */
+    for (;;) {
+       (*work)(fileno(stdin), fileno(stdout));
+
+       if (!decompress || last_member || inptr == insize) break;
+       /* end of file */
+
+       method = get_method(ifd);
+       if (method == -1) return; /* error message already emitted */
+       bytes_out = 0;            /* required for length check */
+    }
+
+    if (verbose) {
+       if (test) {
+           fprintf(stderr, " OK");
+
+       } else if (!decompress) {
+           fprintf(stderr, "Compression: ");
+           display_ratio(bytes_in-bytes_out-overhead, bytes_in);
+       }
+       fprintf(stderr, "\n");
+    }
+}
+
+/* ========================================================================
+ * Compress or decompress the given file
+ */
+local void treat_file(iname)
+    char *iname;
+{
+    /* Check if the input file is present, set ifname and istat: */
+    if (get_istat(iname, &istat) != 0) return;
+
+    /* If the input name is that of a directory, recurse or ignore: */
+    if (S_ISDIR(istat.st_mode)) {
+#ifndef NO_DIR
+       if (recursive) {
+           struct stat st;
+           st = istat;
+           treat_dir(iname);
+           /* Warning: ifname is now garbage */
+           reset_times (iname, &st);
+       } else
+#endif
+       WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
+       return;
+    }
+    if (!S_ISREG(istat.st_mode)) {
+       WARN((stderr,
+             "%s: %s is not a directory or a regular file - ignored\n",
+             progname, ifname));
+       return;
+    }
+    if (istat.st_nlink > 1 && !to_stdout && !force) {
+       WARN((stderr, "%s: %s has %d other link%c -- unchanged\n",
+             progname, ifname,
+             (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
+       return;
+    }
+
+    ifile_size = istat.st_size;
+    time_stamp = istat.st_mtime;
+
+    /* Generate output file name */
+    if (to_stdout) {
+       strcpy(ofname, "stdout");
+
+    } else if (make_ofname() != 0) {
+       return;
+    }
+
+    /* Open the input file and determine compression method. The mode
+     * parameter is ignored but required by some systems (VMS).
+     */
+    ifd = open(ifname, O_RDONLY | O_BINARY, RW_USER);
+    if (ifd == -1) {
+       perror(ifname);
+       exit_code = ERROR;
+       return;
+    }
+    clear_bufs(); /* clear input and output buffers */
+    part_nb = 0;
+
+    if (decompress) {
+       method = get_method(ifd); /* updates ofname if original given */
+       if (method < 0) {
+           close(ifd);
+           return;               /* error message already emitted */
+       }
+    }
+
+    /* If compressing to a file, check if ofname is not ambiguous
+     * because the operating system truncates names. Otherwise, generate
+     * a new ofname and save the original name in the compressed file.
+     */
+    if (to_stdout) {
+       ofd = fileno(stdout);
+       /* keep remove_ofname as zero */
+    } else {
+       if (create_outfile() == -1) return;
+
+       if (save_orig_name && !verbose && !quiet) {
+           fprintf(stderr, "%s: %s compressed to %s\n",
+                   progname, ifname, ofname);
+       }
+    }
+    if (verbose) {
+       fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? 
+               "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
+    }
+
+    /* Actually do the compression/decompression. Loop over zipped members.
+     */
+    for (;;) {
+       (*work)(ifd, ofd);
+
+       if (!decompress || last_member || inptr == insize) break;
+       /* end of file */
+
+       method = get_method(ifd);
+       if (method < 0) break;    /* error message already emitted */
+       bytes_out = 0;            /* required for length check */
+    }
+
+    close(ifd);
+    if (!to_stdout && close(ofd)) {
+       write_error();
+    }
+    if (method == -1) return;     /* error, don't display success msg */
+
+    /* Display statistics */
+    if(verbose) {
+       if (!decompress) {
+           display_ratio(bytes_in-bytes_out-overhead, bytes_in);
+       }
+       if (test) {
+           fprintf(stderr, " OK");
+       } else if (!to_stdout) {
+           fprintf(stderr, " -- replaced with %s", ofname);
+       }
+       fprintf(stderr, "\n");
+    }
+    /* Copy modes, times, ownership */
+    if (!to_stdout) {
+       copy_stat(&istat);
+    }
+}
+
+/* ========================================================================
+ * Create the output file. Return 0 for success, -1 for error.
+ * Try twice if ofname is exactly one beyond the name limit, to avoid
+ * creating a compressed file of name "1234567890123."
+ * We could actually loop more than once if the user gives an extra long
+ * name, but I prefer generating an error then. (Posix forbids the system
+ * to truncate names.) The error message is generated by check_ofname()
+ * in this case.
+ * IN assertions: the input file has already been open (ifd is set) and
+ *   ofname has already been updated if there was an original name.
+ * OUT assertions: ifd and ofd are closed in case of error.
+ */
+local int create_outfile()
+{
+    struct stat        ostat; /* stat for ofname */
+    int n;             /* loop counter */
+
+    for (n = 1; n <= 2; n++) {
+       if (check_ofname() == -1) {
+           close(ifd);
+           return -1;
+       }
+       /* Create the output file */
+       remove_ofname = 1;
+       ofd = open(ofname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, RW_USER);
+       if (ofd == -1) {
+           perror(ofname);
+           close(ifd);
+           exit_code = ERROR;
+           return -1;
+       }
+
+       /* Check for name truncation on new file (1234567890123.z) */
+       if (fstat(ofd, &ostat) != 0) {
+           fprintf(stderr, "%s: ", progname);
+           perror(ofname);
+           close(ifd); close(ofd);
+           unlink(ofname);
+           exit_code = ERROR;
+           return -1;
+       }
+       if (!name_too_long(ofname, &ostat)) return 0;
+
+       if (decompress) {
+           /* name might be too long if an original name was saved */
+           WARN((stderr, "%s: %s: warning, name truncated\n",
+                 progname, ofname));
+           return 0;
+       } else {
+#ifdef NO_MULTIPLE_DOTS
+           /* Should never happen, see check_ofname() */
+           fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
+           do_exit(ERROR);
+#else
+           close(ofd);
+           unlink(ofname);
+           save_orig_name = 1;
+           strcpy(ofname+strlen(ofname)-Z_LEN-1, Z_SUFFIX);
+            /* 1234567890123.z -> 123456789012.z */
+#endif
+       } /* decompress ? */
+    } /* for (n) */
+
+    close(ifd);
+    fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
+    exit_code = ERROR;
+    return -1;
+}
+
+/* ========================================================================
+ * Use lstat if available, except for -c or -f. Use stat otherwise.
+ * This allows links when not removing the original file.
+ */
+local int do_stat(name, sbuf)
+    char *name;
+    struct stat *sbuf;
+{
+#if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
+    if (!to_stdout && !force) {
+       return lstat(name, sbuf);
+    }
+#endif
+    return stat(name, sbuf);
+}
+
+/* ========================================================================
+ * Return a pointer to the 'z' suffix of a file name, or NULL.
+ * For all systems, ".z", ".Z", ".taz", ".tgz", "-z" are accepted suffixes.
+ * ".tgz" is a useful convention for tar.z files on systems limited
+ * to 3 characters extensions. On such systems, ".?z" and ".??z" are
+ * also accepted suffixes. For Unix, we do not want to accept any
+ * .??z suffix as indicating a compressed file; some people use .xyz
+ * to denote volume data.
+ */
+local char *get_suffix(name)
+    char *name;
+{
+    int len;
+    char *p = strrchr(name, '.');
+    char suffix[10];       /* last few chars of name, forced to lower case */
+
+    if (p == NULL || p == name || strchr(p-1, PATH_SEP) != NULL) return NULL;
+    strncpy(suffix, p, sizeof(suffix));
+    suffix[sizeof(suffix)-1] = '\0';    /* Force null termination */
+
+#ifdef SUFFIX_SEP
+    /* strip a version number from the file name */
+    {
+       char *v = strrchr(suffix, SUFFIX_SEP);
+       if (v != NULL) *v = '\0';
+    }
+#endif
+    strlwr(suffix);
+    if (strequ(suffix, ".z") || strequ(suffix, ".zip")
+       || strequ(suffix, ".tgz") || strequ(suffix, ".taz")) {
+       return p;
+    }
+    len = strlen(suffix);
+    if (len <= 2) return NULL;
+
+    if (strequ(suffix+len-2, "-z")) return p+len-2;
+#ifdef MAX_EXT_CHARS
+    if (suffix[len-1] == 'z') return p+len-1;
+#endif
+    return NULL;
+}
+
+
+/* ========================================================================
+ * Set ifname to the input file name (with .z appended if necessary)
+ * and istat to its stats. Return 0 if ok, -1 if error.
+ */
+local int get_istat(iname, sbuf)
+    char *iname;
+    struct stat *sbuf;
+{
+    int iexists; /* set if iname exists */
+    int ilen = strlen(iname);
+    char *suff;
+
+    strcpy(ifname, iname);
+    errno = 0;
+
+    /* If input file exists, return OK. */
+    if (do_stat(ifname, sbuf) == 0) return 0;
+
+    if (!decompress || errno != ENOENT) {
+       perror(ifname);
+       exit_code = ERROR;
+       return -1;
+    }
+    /* file.ext doesn't exist, try file.ext.z and file.ext.Z. For MSDOS
+     * try file.exz, for VMS try file.ext-z.
+     */
+    suff = get_suffix(ifname);
+    if (suff != NULL) {
+       perror(ifname); /* ifname already has z suffix and does not exist */
+       exit_code = ERROR;
+       return -1;
+    }
+#ifdef SUFFIX_SEP
+    /* strip a version number from the input file name */
+    if ((suff = strrchr(ifname, SUFFIX_SEP)) != NULL) *suff = '\0';
+#endif
+    if (strrchr(ifname, '.') != NULL) {
+       strcat(ifname, Z_SUFFIX);
+       ilen += Z_LEN;
+    } else {
+       strcat(ifname, ".z");
+       ilen += 2;
+    }
+    errno = 0;
+    iexists = !do_stat(ifname, sbuf);
+    if (!iexists) {
+       errno = 0;
+       ifname[ilen-1] = 'Z';
+       iexists = !do_stat(ifname, sbuf);
+    }
+#ifdef NO_MULTIPLE_DOTS
+    /* One more try just to be nice to you */
+    if (!iexists) {
+       char c = ifname[ilen-2];
+       errno = 0;
+       strcpy(ifname+ilen-2, "z");
+       iexists = !do_stat(ifname, sbuf);
+       if (!iexists) {
+           ifname[ilen-2] = c;
+       }
+    }
+#endif
+    if (!iexists) {
+       ifname[ilen-1] = 'z';
+       perror(ifname);
+       exit_code = ERROR;
+       return -1;
+    }
+    if (!S_ISREG (sbuf->st_mode)) {
+       WARN((stderr, "%s: %s: not a regular file -- ignored\n",
+             progname, ifname));
+       return -1;
+    }
+    return 0; /* ok */
+}
+
+/* ========================================================================
+ * Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped.
+ * Initializes save_orig_name.
+ * IN assertion: this function is not called if to_stdout is true.
+ */
+local int make_ofname()
+{
+    char *suff;            /* ofname z suffix */
+
+    strcpy(ofname, ifname);
+    suff = get_suffix(ofname);
+
+    if (decompress) {
+       if (suff == NULL) {
+           WARN((stderr,"%s: %s: no z suffix -- ignored\n",
+                 progname, ifname));
+           return -1;
+       }
+       /* Make a special case for .tgz and .taz: */
+       strlwr(suff);
+       if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
+           strcpy(suff, ".tar");
+       } else {
+           *suff = '\0'; /* strip z suffix and optional version number */
+       }
+        /* ofname might be changed later if infile contains an original name */
+
+    } else if (suff != NULL) {
+       /* Avoid annoying messages with -r (see treat_dir()) */
+       if (verbose || (!recursive && !quiet)) {
+           fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
+                   progname, ifname, suff);
+       }
+       if (exit_code == OK) exit_code = WARNING;
+       return -1;
+    } else {
+        save_orig_name = 0;
+
+#ifdef SUFFIX_SEP
+       /* strip a version number from the file name */
+       if ((suff = strrchr(ofname, SUFFIX_SEP)) != NULL) *suff = '\0';
+#endif
+
+#ifdef NO_MULTIPLE_DOTS
+       suff = strrchr(ofname, '.');
+       if (suff != NULL) {
+#  ifdef MAX_EXT_CHARS
+           /* On the Atari and some versions of MSDOS, name_too_long()
+            * does not work correctly because of a bug in stat(). So we
+            * must truncate here.
+            */
+           if (strlen(suff) > MAX_EXT_CHARS) {
+               strcpy(suff + MAX_EXT_CHARS, do_lzw ? "Z" : "z");
+               save_orig_name = 1;
+               return 0;
+           }
+#  endif
+           strcat(ofname, Z_SUFFIX);
+           return 0;
+       }
+#endif
+       strcat(ofname, do_lzw ? ".Z" : ".z");
+
+    } /* decompress ? */
+    return 0;
+}
+
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ *   If the member is a zip file, it must be the only one.
+ */
+local int get_method(in)
+    int in;        /* input file descriptor */
+{
+    uch flags;
+    char magic[2]; /* magic header */
+
+    magic[0] = (char)get_byte();
+    magic[1] = (char)get_byte();
+
+    time_stamp = istat.st_mtime; /* may be modified later for some methods */
+    method = -1;                 /* unknown yet */
+    part_nb++;                   /* number of parts in gzip file */
+    last_member = RECORD_IO;
+    /* assume multiple members in gzip file except for record oriented I/O */
+
+    if (memcmp(magic, GZIP_MAGIC, 2) == 0
+        || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+       work = unzip;
+       method = (int)get_byte();
+       flags  = (uch)get_byte();
+
+       if ((flags & ENCRYPTED) != 0) {
+           fprintf(stderr,
+                   "%s: %s is encrypted -- get newer version of gzip\n",
+                   progname, ifname);
+           exit_code = ERROR;
+           return -1;
+       }
+       if ((flags & CONTINUATION) != 0) {
+           fprintf(stderr,
+          "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
+                   progname, ifname);
+           exit_code = ERROR;
+           if (force <= 1) return -1;
+       }
+       if ((flags & RESERVED) != 0) {
+           fprintf(stderr,
+                   "%s: %s has flags 0x%x -- get newer version of gzip\n",
+                   progname, ifname, flags);
+           exit_code = ERROR;
+           if (force <= 1) return -1;
+       }
+       time_stamp  = (ulg)get_byte();
+       time_stamp |= ((ulg)get_byte()) << 8;
+       time_stamp |= ((ulg)get_byte()) << 16;
+       time_stamp |= ((ulg)get_byte()) << 24;
+
+       (void)get_byte();  /* Ignore extra flags for the moment */
+       (void)get_byte();  /* Ignore OS type for the moment */
+
+       if ((flags & CONTINUATION) != 0) {
+           unsigned part = (unsigned)get_byte();
+           part |= ((unsigned)get_byte())<<8;
+           if (verbose) {
+               fprintf(stderr,"%s: %s: part number %u\n",
+                       progname, ifname, part);
+           }
+       }
+       if ((flags & EXTRA_FIELD) != 0) {
+           unsigned len = (unsigned)get_byte();
+           len |= ((unsigned)get_byte())<<8;
+           if (verbose) {
+               fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
+                       progname, ifname, len);
+           }
+           while (len--) (void)get_byte();
+       }
+
+       /* Get original file name if it was truncated */
+       if ((flags & ORIG_NAME) != 0) {
+           if (to_stdout || part_nb > 1) {
+               /* Discard the old name */
+               while (get_byte() != 0) /* null */ ;
+           } else {
+               /* Copy the base name. Keep a directory prefix intact. */
+               char *p = basename(ofname);
+               for (;;) {
+                   *p = (char)get_byte();
+                   if (*p++ == '\0') break;
+                   if (p >= ofname+sizeof(ofname)) {
+                       error("corrupted input -- file name too large");
+                   }
+               }
+           } /* to_stdout */
+       } /* orig_name */
+
+       /* Discard file comment if any */
+       if ((flags & COMMENT) != 0) {
+           while (get_byte() != 0) /* null */ ;
+       }
+
+    } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
+           && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) {
+       /* To simplify the code, we support a zip file when alone only.
+         * We are thus guaranteed that the entire local header fits in inbuf.
+         */
+        inptr = 0;
+       work = unzip;
+       if (check_zipfile(in) == -1) return -1;
+       /* check_zipfile may get ofname from the local header */
+       last_member = 1;
+
+    } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
+       work = unpack;
+       method = PACKED;
+    } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
+       work = unlzw;
+       method = COMPRESSED;
+       last_member = 1;
+    }
+    if (method >= 0) return method;
+    if (part_nb == 1) {
+       fprintf(stderr, "%s: %s is not in gzip format\n", progname, ifname);
+       exit_code = ERROR;
+       return -1;
+    } else {
+       WARN((stderr, "%s: %s: trailing garbage ignored\n", progname, ifname));
+       return -2;
+    }
+}
+
+/* ========================================================================
+ * Return true if the two stat structures correspond to the same file.
+ */
+local int same_file(stat1, stat2)
+    struct stat *stat1;
+    struct stat *stat2;
+{
+    return stat1->st_mode  == stat2->st_mode
+       && stat1->st_ino   == stat2->st_ino
+       && stat1->st_dev   == stat2->st_dev
+       && stat1->st_uid   == stat2->st_uid
+       && stat1->st_gid   == stat2->st_gid
+       && stat1->st_size  == stat2->st_size
+       && stat1->st_atime == stat2->st_atime
+       && stat1->st_mtime == stat2->st_mtime
+       && stat1->st_ctime == stat2->st_ctime;
+}
+
+/* ========================================================================
+ * Return true if a file name is ambiguous because the operating system
+ * truncates file names.
+ */
+local int name_too_long(name, statb)
+    char *name;           /* file name to check */
+    struct stat *statb;   /* stat buf for this file name */
+{
+    int s = strlen(name);
+    char c = name[s-1];
+    struct stat        tstat; /* stat for truncated name */
+    int res;
+
+    tstat = *statb;      /* Just in case OS does not fill all fields */
+    name[s-1] = '\0';
+    res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
+    name[s-1] = c;
+    return res;
+}
+
+/* ========================================================================
+ * If compressing to a file, check if ofname is not ambigous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ * If the compressed file already exists, ask for confirmation.
+ *    The check for name truncation is made dynamically, because different
+ * file systems on the same OS might use different truncation rules (on SVR4
+ * s5 truncates to 14 chars and ufs does not truncate).
+ *    This function returns -1 if the file must be skipped, and
+ * updates save_orig_name if necessary.
+ * IN assertions: save_orig_name is already set if ofname has been
+ * already truncated because of NO_MULTIPLE_DOTS. The input file has
+ * already been open and istat is set.
+ */
+local int check_ofname()
+{
+    int s = strlen(ofname);
+    struct stat        ostat; /* stat for ofname */
+
+    if (stat(ofname, &ostat) != 0) return 0;
+
+    /* Check for name truncation on existing file: */
+#ifdef NO_MULTIPLE_DOTS
+    if (!decompress && name_too_long(ofname, &ostat)) {
+#else
+    if (!decompress && s > 8 && name_too_long(ofname, &ostat)) {
+#endif
+       save_orig_name = 1;
+#ifdef NO_MULTIPLE_DOTS
+       strcpy(ofname+s-Z_LEN-1, Z_SUFFIX);  /* f.extz -> f.exz  */
+#else
+       strcpy(ofname+s-4, ".z"); /* 12345678901234.z -> 123456789012.z */
+#endif
+       if (stat(ofname, &ostat) != 0) return 0;
+    } /* !decompress && name_too_long */
+
+    /* Check that the input and output files are different (could be
+     * the same by name truncation or links).
+     */
+    if (same_file(&istat, &ostat)) {
+       fprintf(stderr, "%s: %s and %s are the same file\n",
+               progname, ifname, ofname);
+       exit_code = ERROR;
+       return -1;
+    }
+    /* Ask permission to overwrite the existing file */
+    if (!force) {
+       char response[80];
+       strcpy(response,"n");
+       fprintf(stderr, "%s: %s already exists;", progname, ofname);
+       if (foreground && isatty(fileno(stdin))) {
+           fprintf(stderr, " do you wish to overwrite (y or n)? ");
+           fflush(stderr);
+           (void)read(fileno(stdin), response, sizeof(response));
+       }
+       if (tolow(*response) != 'y') {
+           fprintf(stderr, "\tnot overwritten\n");
+           if (exit_code == OK) exit_code = WARNING;
+           return -1;
+       }
+    }
+    (void) chmod(ofname, 0777);
+    if (unlink(ofname)) {
+       fprintf(stderr, "%s: ", progname);
+       perror(ofname);
+       exit_code = ERROR;
+       return -1;
+    }
+    return 0;
+}
+
+
+/* ========================================================================
+ * Set the access and modification times from the given stat buffer.
+ */
+local void reset_times (name, statb)
+    char *name;
+    struct stat *statb;
+{
+#ifndef NO_UTIME
+    struct utimbuf     timep;
+
+    /* Copy the time stamp */
+    timep.actime  = statb->st_atime;
+    timep.modtime = statb->st_mtime;
+
+    if (utime(name, &timep)) {
+       WARN((stderr, "%s: ", progname));
+       if (!quiet) perror(ofname);
+    }
+#else
+    name = name; statb = statb; /* avoid warnings */
+#endif
+}
+
+
+/* ========================================================================
+ * Copy modes, times, ownership from input file to output file.
+ * IN assertion: to_stdout is false.
+ */
+local void copy_stat(ifstat)
+    struct stat *ifstat;
+{
+#ifndef NO_UTIME
+    time_t diff = ifstat->st_mtime - time_stamp;
+
+    if (diff < 0) diff = -diff;
+    if (decompress && diff > 60 && time_stamp != 0) {
+       ifstat->st_mtime = time_stamp;
+       if (verbose) {
+           fprintf(stderr, "%s: time stamp restored\n", ofname);
+       }
+    }
+    reset_times(ofname, ifstat);
+#endif
+    /* Copy the protection modes */
+    if (chmod(ofname, ifstat->st_mode & 07777)) {
+       WARN((stderr, "%s: ", progname));
+       if (!quiet) perror(ofname);
+    }
+#ifndef NO_CHOWN
+    chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
+#endif
+    remove_ofname = 0;
+    /* It's now safe to remove the input file: */
+    (void) chmod(ifname, 0777);
+    if (unlink(ifname)) {
+       WARN((stderr, "%s: ", progname));
+       if (!quiet) perror(ifname);
+    }
+}
+
+#ifndef NO_DIR
+
+/* ========================================================================
+ * Recurse through the given directory. This code is taken from ncompress.
+ */
+local void treat_dir(dir)
+    char *dir;
+{
+    dir_type *dp;
+    DIR      *dirp;
+    char     nbuf[MAX_PATH_LEN];
+
+    dirp = opendir(dir);
+    
+    if (dirp == NULL) {
+       fprintf(stderr, "%s: %s unreadable\n", progname, dir);
+       exit_code = ERROR;
+       return ;
+    }
+    /*
+     ** WARNING: the following algorithm could occasionally cause
+     ** compress to produce error warnings of the form "<filename>.z
+     ** already has .z suffix - ignored". This occurs when the
+     ** .z output file is inserted into the directory below
+     ** readdir's current pointer.
+     ** These warnings are harmless but annoying, so they are suppressed
+     ** with option -r (except when -v is on). An alternative
+     ** to allowing this would be to store the entire directory
+     ** list in memory, then compress the entries in the stored
+     ** list. Given the depth-first recursive algorithm used here,
+     ** this could use up a tremendous amount of memory. I don't
+     ** think it's worth it. -- Dave Mack
+     ** (An other alternative might be two passes to avoid depth-first.)
+     */
+    
+    while ((dp = readdir(dirp)) != NULL) {
+
+       if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
+           continue;
+       }
+       if (((int)strlen(dir) + NLENGTH(dp) + 1) < (MAX_PATH_LEN - 1)) {
+           strcpy(nbuf,dir);
+           if (strlen(dir) != 0) { /* dir = "" means current dir on Amiga */
+#ifdef OTHER_PATH_SEP
+               if (dir[strlen(dir)-1] != OTHER_PATH_SEP)
+#endif
+               strcat(nbuf,"/");
+           }
+           strcat(nbuf,dp->d_name);
+           treat_file(nbuf);
+       } else {
+           fprintf(stderr,"%s: %s/%s: pathname too long\n",
+                   progname, dir, dp->d_name);
+           exit_code = ERROR;
+       }
+    }
+    closedir(dirp);
+}
+#endif /* ? NO_DIR */
+
+/* ========================================================================
+ * Free all dynamically allocated variables and exit with the given code.
+ */
+local void do_exit(exitcode)
+    int exitcode;
+{
+    if (env != NULL)  free(env),  env  = NULL;
+    if (args != NULL) free(args), args = NULL;
+    FREE(inbuf);
+    FREE(outbuf);
+    FREE(d_buf);
+    FREE(window);
+#ifndef MAXSEG_64K
+    FREE(tab_prefix);
+#else
+    FREE(tab_prefix0);
+    FREE(tab_prefix1);
+#endif
+    exit(exitcode);
+}
+
+/* ========================================================================
+ * Signal and error handler.
+ */
+RETSIGTYPE abort_gzip()
+{
+   if (remove_ofname) {
+       close(ofd);
+       unlink (ofname);
+   }
+   do_exit(ERROR);
+}
diff --git a/usr/src/contrib/gzip/gzip.h b/usr/src/contrib/gzip/gzip.h
new file mode 100644 (file)
index 0000000..42a308d
--- /dev/null
@@ -0,0 +1,288 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+#  define OF(args)  args
+#else
+#  define OF(args)  ()
+#endif
+
+#ifdef __STDC__
+   typedef void *voidp;
+#else
+   typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string functions are used too often */
+#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
+#  include <string.h>
+#  if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H)
+#    include <memory.h>
+#  endif
+#  define memzero(s, n)     memset ((voidp)(s), 0, (n))
+#else
+#  include <strings.h>
+#  define strchr            index 
+#  define strrchr           rindex
+#  define memcpy(d, s, n)   bcopy((s), (d), (n)) 
+#  define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) 
+#  define memzero(s, n)     bzero((s), (n))
+#endif
+
+#ifndef RETSIGTYPE
+#  define RETSIGTYPE void
+#endif
+
+#define local static
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+/* Return codes from gzip */
+#define OK      0
+#define ERROR   1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED     0
+#define COMPRESSED 1
+#define PACKED     2
+/* methods 3 to 7 reserved */
+#define DEFLATED   8
+extern int method;         /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate:  prev+head   window      d_buf  l_buf  outbuf
+ * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
+ * inflate:              window             inbuf
+ * unpack:               window             inbuf
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef        INBUFSIZ
+#  define INBUFSIZ  0x8000  /* input buffer size */
+#endif
+#define INBUF_EXTRA  64     /* required by unlzw() */
+
+#ifndef        OUTBUFSIZ
+#  define OUTBUFSIZ  16384  /* output buffer size */
+#endif
+#define OUTBUF_EXTRA 2048   /* required by unlzw() */
+
+#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+
+#ifdef DYN_ALLOC
+#  define EXTERN(type, array)  extern type * near array
+#  define DECLARE(type, array, size)  type * near array
+#  define ALLOC(type, array, size) { \
+      array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
+      if (array == NULL) error("insufficient memory"); \
+   }
+#  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+#  define EXTERN(type, array)  extern type array[]
+#  define DECLARE(type, array, size)  type array[size]
+#  define ALLOC(type, array, size)
+#  define FREE(array)
+#endif
+
+EXTERN(uch, inbuf);          /* input buffer */
+EXTERN(uch, outbuf);         /* output buffer */
+EXTERN(ush, d_buf);          /* buffer for distances, see trees.c */
+EXTERN(uch, window);         /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+#  define tab_prefix prev    /* hash link (see deflate.c) */
+#  define head (prev+WSIZE)  /* hash head (see deflate.c) */
+   EXTERN(ush, tab_prefix);  /* prefix code (see unlzw.c) */
+#else
+#  define tab_prefix0 prev
+#  define head tab_prefix1
+   EXTERN(ush, tab_prefix0); /* prefix for even codes */
+   EXTERN(ush, tab_prefix1); /* prefix for odd  codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr;  /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in;   /* number of input bytes */
+extern long bytes_out;  /* number of output bytes */
+extern long overhead;   /* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int  ifd;        /* input file descriptor */
+extern int  ofd;        /* output file descriptor */
+extern char ifname[];   /* input filename or "stdin" */
+extern char ofname[];   /* output filename or "stdout" */
+extern char *progname;  /* program name */
+
+extern ulg time_stamp;  /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+typedef int file_t;     /* Do not use stdio */
+#define NO_FILE  (-1)   /* in memory compression */
+
+
+#define        GZIP_MAGIC     "\037\213" /* Magic header for gzip files, 1F 8B */
+#define        OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define        PKZIP_MAGIC  "PK\003\004" /* Magic header for pkzip files */
+#define        PACK_MAGIC     "\037\036" /* Magic header for packed files */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY  0
+#define ASCII   1
+
+#ifndef WSIZE
+#  define WSIZE 0x8000     /* window size--must be a power of two, and */
+#endif                     /*  at least 32K for zip's deflate method */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt;        /* flag to turn on decryption */
+extern int exit_code;      /* program exit code */
+extern int verbose;        /* be verbose (-v) */
+extern int quiet;          /* be quiet (-q) */
+extern int level;          /* compression level */
+extern int test;           /* check .z file integrity */
+extern int to_stdout;      /* output to stdout (-c) */
+extern int save_orig_name; /* set if original name must be saved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* put_byte is used for the compressed output, put_char for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_char.
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+   flush_outbuf();}
+#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+   flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+    outbuf[outcnt++] = (uch) ((w) & 0xff); \
+    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+  } else { \
+    put_byte((uch)((w) & 0xff)); \
+    put_byte((uch)((ush)(w) >> 8)); \
+  } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+    put_short((n) & 0xffff); \
+    put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable()    0  /* force sequential output */
+#define translate_eol 0  /* no option -a yet */
+
+#define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+                  if (exit_code == OK) exit_code = WARNING;}
+
+       /* in zip.c: */
+extern void zip    OF((int in, int out));
+extern int file_read  OF((char *buf,  unsigned size));
+
+       /* in unzip.c */
+extern void unzip        OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+       /* in unpack.c */
+extern void unpack        OF((int in, int out));
+
+       /* in gzip.c */
+RETSIGTYPE abort_gzip   OF((void));
+
+        /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg  deflate OF((void));
+
+        /* in trees.c */
+void ct_init     OF((ush *attr, int *method));
+int  ct_tally    OF((int dist, int lc));
+ulg  flush_block OF((char *buf, ulg stored_len, int eof));
+
+        /* in bits.c */
+void     bi_init    OF((file_t zipfile));
+void     send_bits  OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void     bi_windup  OF((void));
+void     copy_block OF((char *buf, unsigned len, int header));
+extern   int (*read_buf) OF((char *buf, unsigned size));
+
+       /* in util.c: */
+extern ulg  updcrc        OF((uch *s, unsigned n));
+extern void clear_bufs    OF((void));
+extern int  fill_inbuf    OF((void));
+extern void flush_outbuf  OF((void));
+extern void flush_window  OF((void));
+extern void write_buf     OF((int fd, voidp buf, unsigned cnt));
+extern char *strlwr       OF((char *s));
+extern char *basename     OF((char *fname));
+extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
+extern void error         OF((char *m));
+extern void warn          OF((char *a, char *b));
+extern void read_error    OF((void));
+extern void write_error   OF((void));
+extern void display_ratio OF((long num, long den));
+extern voidp xmalloc      OF((unsigned int size));
+
+       /* in inflate.c */
+extern int inflate OF((void));
diff --git a/usr/src/contrib/gzip/inflate.c b/usr/src/contrib/gzip/inflate.c
new file mode 100644 (file)
index 0000000..de2589f
--- /dev/null
@@ -0,0 +1,952 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+   prefer that if you modify it and redistribute it that you include
+   comments to that effect with your name and the date.  Thank you.
+   [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
+   method searches for as much of the current string of bytes (up to a
+   length of 258) in the previous 32K bytes.  If it doesn't find any
+   matches (of at least length 3), it codes the next byte.  Otherwise, it
+   codes the length of the matched string and its distance backwards from
+   the current position.  There is a single Huffman code that codes both
+   single bytes (called "literals") and match lengths.  A second Huffman
+   code codes the distance information, which follows a length code.  Each
+   length or distance code actually represents a base value and a number
+   of "extra" (sometimes zero) bits to get to add to the base value.  At
+   the end of each deflated block is a special end-of-block (EOB) literal/
+   length code.  The decoding process is basically: get a literal/length
+   code; if EOB then done; if a literal, emit the decoded byte; if a
+   length then get the distance and emit the referred-to bytes from the
+   sliding window of previously emitted data.
+
+   There are (currently) three kinds of inflate blocks: stored, fixed, and
+   dynamic.  The compressor deals with some chunk of data at a time, and
+   decides which method to use on a chunk-by-chunk basis.  A chunk might
+   typically be 32K or 64K.  If the chunk is uncompressible, then the
+   "stored" method is used.  In this case, the bytes are simply stored as
+   is, eight bits per byte, with none of the above coding.  The bytes are
+   preceded by a count, since there is no longer an EOB code.
+
+   If the data is compressible, then either the fixed or dynamic methods
+   are used.  In the dynamic method, the compressed data is preceded by
+   an encoding of the literal/length and distance Huffman codes that are
+   to be used to decode this block.  The representation is itself Huffman
+   coded, and so is preceded by a description of that code.  These code
+   descriptions take up a little space, and so for small blocks, there is
+   a predefined set of codes, called the fixed codes.  The fixed method is
+   used if the block codes up smaller that way (usually for quite small
+   chunks), otherwise the dynamic method is used.  In the latter case, the
+   codes are customized to the probabilities in the current block, and so
+   can code it much better than the pre-determined fixed codes.
+   The Huffman codes themselves are decoded using a mutli-level table
+   lookup, in order to maximize the speed of decoding plus the speed of
+   building the decoding tables.  See the comments below that precede the
+   lbits and dbits tuning parameters.
+ */
+
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarly, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: inflate.c,v 0.12 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#define slide window
+
+#include <stdio.h>
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+#  include <sys/types.h>
+#  include <stdlib.h>
+#endif
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+struct huft {
+  uch e;                /* number of extra bits or operation */
+  uch b;                /* number of bits in this code or subcode */
+  union {
+    ush n;              /* literal, length base, or distance base */
+    struct huft *t;     /* pointer to next level of table */
+  } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+                   struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+/* unsigned wp;             current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = {    /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = {         /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+static ush cpdext[] = {         /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+   
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed, and are initialized at the beginning of a
+   routine that uses these macros from a global bit buffer and count.
+
+   If we assume that EOB will be the longest code, then we will never
+   ask for bits with NEEDBITS that are beyond the end of the stream.
+   So, NEEDBITS should not read any more bytes than are needed to
+   meet the request.  Then no bytes need to be "returned" to the buffer
+   at the end of the last block.
+
+   However, this assumption is not true for fixed blocks--the EOB code
+   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+   (The EOB code is shorter than other codes becuase fixed blocks are
+   generally short.  So, while a block always has an EOB, many other
+   literal/length codes have a significantly lower probability of
+   showing up at all.)  However, by making the first table have a
+   lookup of seven bits, the EOB code will be found in that first
+   lookup, and so will not require that too many bits be pulled from
+   the stream.
+ */
+
+ulg bb;                         /* bit buffer */
+unsigned bk;                    /* bits in bit buffer */
+
+ush mask_bits[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+  uch cc;
+#  define NEXTBYTE() \
+     (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
+#else
+#  define NEXTBYTE()  (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+int lbits = 9;          /* bits in base literal/length lookup table */
+int dbits = 6;          /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+unsigned hufts;         /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
+unsigned n;             /* number of codes (assumed <= N_MAX) */
+unsigned s;             /* number of simple-valued codes (0..s-1) */
+ush *d;                 /* list of base values for non-simple codes */
+ush *e;                 /* list of extra bits for non-simple codes */
+struct huft **t;        /* result: starting table */
+int *m;                 /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX+1];           /* bit length count table */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  memzero(c, sizeof(c));
+  p = b;  i = n;
+  do {
+    Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
+           n-i, *p));
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (struct huft *)NULL;
+    *m = 0;
+    return 0;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
+  q = (struct huft *)NULL;      /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          while (++j < z)       /* try smaller tables up to z bits */
+          {
+            if ((f <<= 1) <= *++xp)
+              break;            /* enough codes to use up j bits */
+            f -= *xp;           /* else deduct codes from patterns */
+          }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+            (struct huft *)NULL)
+        {
+          if (h)
+            huft_free(u[0]);
+          return 3;             /* not enough memory */
+        }
+        hufts += z + 1;         /* track memory usage */
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = (struct huft *)NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uch)l;         /* bits to dump before this table */
+          r.e = (uch)(16 + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.b = (uch)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
+        r.v.n = *p++;           /* simple code is just the value */
+      }
+      else
+      {
+        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t;         /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *)NULL)
+  {
+    q = (--p)->v.t;
+    free(p);
+    p = q;
+  } 
+  return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td;   /* literal/length and distance decoder tables */
+int bl, bd;             /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  for (;;)                      /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+      do {
+        if (e == 99)
+          return 1;
+        DUMPBITS(t->b)
+        e -= 16;
+        NEEDBITS(e)
+      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+    DUMPBITS(t->b)
+    if (e == 16)                /* then it's a literal */
+    {
+      slide[w++] = (uch)t->v.n;
+      Tracevv((stderr, "%c", slide[w-1]));
+      if (w == WSIZE)
+      {
+        flush_output(w);
+        w = 0;
+      }
+    }
+    else                        /* it's an EOB or a length */
+    {
+      /* exit if end of block */
+      if (e == 15)
+        break;
+
+      /* get length of block to copy */
+      NEEDBITS(e)
+      n = t->v.n + ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e);
+
+      /* decode distance of block to copy */
+      NEEDBITS((unsigned)bd)
+      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      NEEDBITS(e)
+      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e)
+      Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+      /* do the copy */
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+        if (w - d >= e)         /* (this test assumes unsigned comparison) */
+        {
+          memcpy(slide + w, slide + d, e);
+          w += e;
+          d += e;
+        }
+        else                      /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+          do {
+            slide[w++] = slide[d++];
+           Tracevv((stderr, "%c", slide[w-1]));
+          } while (--e);
+        if (w == WSIZE)
+        {
+          flush_output(w);
+          w = 0;
+        }
+      } while (n);
+    }
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  /* done */
+  return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  unsigned n;           /* number of bytes in block */
+  unsigned w;           /* current window position */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    slide[w++] = (uch)b;
+    if (w == WSIZE)
+    {
+      flush_output(w);
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+  return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  int i;                /* temporary variable */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned l[288];      /* length list for huft_build */
+
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  bl = 7;
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+    return i;
+
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  bd = 5;
+  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+  {
+    huft_free(tl);
+    return i;
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+  unsigned ll[288+32];  /* literal/length and distance code lengths */
+#else
+  unsigned ll[286+30];  /* literal/length and distance code lengths */
+#endif
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+  if (nl > 288 || nd > 32)
+#else
+  if (nl > 286 || nd > 30)
+#endif
+    return 1;                   /* bad lengths */
+
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+  {
+    if (i == 1)
+      huft_free(tl);
+    return i;                   /* incomplete code set */
+  }
+
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+  {
+    if (i == 1) {
+      fprintf(stderr, " incomplete literal tree\n");
+      huft_free(tl);
+    }
+    return i;                   /* incomplete code set */
+  }
+  bd = dbits;
+  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+  {
+    if (i == 1) {
+      fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+      i = 0;
+    }
+#else
+      huft_free(td);
+    }
+    huft_free(tl);
+    return i;                   /* incomplete code set */
+#endif
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+int inflate_block(e)
+int *e;                 /* last block flag */
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic();
+  if (t == 0)
+    return inflate_stored();
+  if (t == 1)
+    return inflate_fixed();
+
+
+  /* bad block type */
+  return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+  int e;                /* last block flag */
+  int r;                /* result code */
+  unsigned h;           /* maximum struct huft's malloc'ed */
+
+
+  /* initialize window, bit buffer */
+  wp = 0;
+  bk = 0;
+  bb = 0;
+
+
+  /* decompress until the last block */
+  h = 0;
+  do {
+    hufts = 0;
+    if ((r = inflate_block(&e)) != 0)
+      return r;
+    if (hufts > h)
+      h = hufts;
+  } while (!e);
+
+  /* Undo too much lookahead. The next read will be byte aligned so we
+   * can discard unused bits in the last meaningful byte.
+   */
+  while (bk >= 8) {
+    bk -= 8;
+    inptr--;
+  }
+
+  /* flush out slide */
+  flush_output(wp);
+
+
+  /* return success */
+#ifdef DEBUG
+  fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+  return 0;
+}
diff --git a/usr/src/contrib/gzip/lzw.c b/usr/src/contrib/gzip/lzw.c
new file mode 100644 (file)
index 0000000..b73738a
--- /dev/null
@@ -0,0 +1,26 @@
+/* lzw.c -- compress files in LZW format.
+ * This is a dummy version avoiding patent problems.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: lzw.c,v 0.7 1993/02/10 16:07:22 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h"
+
+#include <stdio.h>
+
+static int msg_done = 0;
+
+/* Compress in to out with lzw method. */
+void lzw(in, out) 
+    int in, out;
+{
+    if (msg_done) return;
+    msg_done = 1;
+    fprintf(stderr,"output in compress .Z format not supported\n");
+    in++, out++; /* avoid warnings on unused variables */
+    exit_code = ERROR;
+}
diff --git a/usr/src/contrib/gzip/lzw.h b/usr/src/contrib/gzip/lzw.h
new file mode 100644 (file)
index 0000000..4e640f5
--- /dev/null
@@ -0,0 +1,42 @@
+/* lzw.h -- define the lzw functions.
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if !defined(OF) && defined(lint)
+#  include "gzip.h"
+#endif
+
+#ifndef BITS
+#  define BITS 16
+#endif
+#define INIT_BITS 9              /* Initial number of bits per code */
+
+#define        LZW_MAGIC  "\037\235"   /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK    0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE  0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define        CLEAR  256       /* flush the dictionary */
+#define FIRST  (CLEAR+1) /* first free entry */
+
+extern int maxbits;      /* max bits per code for LZW */
+extern int block_mode;   /* block compress mode -C compatible with 2.0 */
+
+extern void lzw    OF((int in, int out));
+extern void unlzw  OF((int in, int out));
diff --git a/usr/src/contrib/gzip/match.S b/usr/src/contrib/gzip/match.S
new file mode 100644 (file)
index 0000000..d6c454a
--- /dev/null
@@ -0,0 +1,377 @@
+/* match.s -- optional optimized asm version of longest match in deflate.c
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The 68020 version has been written by Francesco Potorti` <pot@cnuce.cnr.it>
+ * adapted to the 68000 by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+ * and Andreas Schwab <schwab@lamothe.informatik.uni-dortmund.de>.
+ */
+/* $Id: match.S,v 0.12 1993/03/18 18:14:56 jloup Exp $ */
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#ifdef NO_UNDERLINE
+#  define _prev             prev
+#  define _window           window
+#  define _match_start     match_start
+#  define _prev_length     prev_length
+#  define _good_match      good_match
+#  define _nice_match      nice_match
+#  define _strstart        strstart
+#  define _max_chain_length max_chain_length
+
+#  define _match_init       match_init
+#  define _longest_match    longest_match
+#endif
+
+#ifdef DYN_ALLOC
+  error: DYN_ALLOC not yet supported in match.s
+#endif
+
+#if defined(i386) || defined(_I386)
+
+/* This version is for 386 Unix or OS/2 in 32 bit mode.
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to force the C version,
+ * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+ * If you have reduced WSIZE in gzip.h, then change its value below.
+ * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+ */
+
+       .file   "match.S"
+
+#define MAX_MATCH      258
+#define MAX_MATCH2      128     /* MAX_MATCH/2-1 */
+#define MIN_MATCH      3
+#define WSIZE          32768
+#define MAX_DIST       WSIZE - MAX_MATCH - MIN_MATCH - 1
+
+       .globl  _match_init
+       .globl  _longest_match
+
+       .text
+
+_match_init:
+       ret
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+_longest_match:        /* int longest_match(cur_match) */
+
+#define cur_match   20(%esp)
+     /* return address */               /* esp+16 */
+        push    %ebp                    /* esp+12 */
+        push    %edi                    /* esp+8  */
+       push    %esi                    /* esp+4  */
+       push    %ebx                    /* esp    */
+
+/*
+ *      match        equ esi
+ *      scan         equ edi
+ *      chain_length equ ebp
+ *      best_len     equ ebx
+ *      limit        equ edx
+ */
+       mov     cur_match,%esi
+        mov    _max_chain_length,%ebp /* chain_length = max_chain_length */
+       mov     _strstart,%edi
+       mov     %edi,%edx
+       sub     $ MAX_DIST,%edx        /* limit = strstart-MAX_DIST */
+       jae     limit_ok
+       sub     %edx,%edx              /* limit = NIL */
+limit_ok:
+        add    $ _window+2,%edi       /* edi = offset(window+strstart+2) */
+        mov    _prev_length,%ebx      /* best_len = prev_length */
+        movw   -3(%ebx,%edi),%ax      /* ax = scan[best_len-1..best_len] */
+        movw   -2(%edi),%cx           /* cx = scan[0..1] */
+       cmp     _good_match,%ebx       /* do we have a good match already? */
+        jb      do_scan
+       shr     $2,%ebp                /* chain_length >>= 2 */
+        jmp     do_scan
+
+        .align  4
+long_loop:
+/* at this point, edi == scan+2, esi == cur_match */
+        movw   -3(%ebx,%edi),%ax       /* ax = scan[best_len-1..best_len] */
+        movw     -2(%edi),%cx           /* cx = scan[0..1] */
+short_loop:
+/*
+ * at this point, di == scan+2, si == cur_match,
+ * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ */
+        and     $ WSIZE-1, %esi
+        movw    _prev(%esi,%esi),%si    /* cur_match = prev[cur_match] */
+                                        /* top word of esi is still 0 */
+        cmp     %edx,%esi              /* cur_match <= limit ? */
+        jbe     the_end
+        dec     %ebp                    /* --chain_length */
+        jz      the_end
+do_scan:
+        cmpw    _window-1(%ebx,%esi),%ax/* check match at best_len-1 */
+        jne     short_loop
+        cmpw    _window(%esi),%cx       /* check min_match_length match */
+        jne     short_loop
+
+        lea     _window+2(%esi),%esi    /* si = match */
+        mov     %edi,%eax               /* ax = scan+2 */
+        mov    $ MAX_MATCH2,%ecx       /* scan for at most MAX_MATCH bytes */
+        rep;    cmpsw                   /* loop until mismatch */
+        je      maxmatch                /* match of length MAX_MATCH? */
+mismatch:
+        movb    -2(%edi),%cl        /* mismatch on first or second byte? */
+        subb    -2(%esi),%cl        /* cl = 0 if first bytes equal */
+        xchg    %edi,%eax           /* edi = scan+2, eax = end of scan */
+        sub     %edi,%eax           /* eax = len */
+       sub     %eax,%esi           /* esi = cur_match + 2 + offset(window) */
+       sub     $ _window+2,%esi    /* esi = cur_match */
+        subb    $1,%cl              /* set carry if cl == 0 (cannot use DEC) */
+        adc     $0,%eax             /* eax = carry ? len+1 : len */
+        cmp     %ebx,%eax           /* len > best_len ? */
+        jle     long_loop
+        mov     %esi,_match_start       /* match_start = cur_match */
+        mov     %eax,%ebx               /* ebx = best_len = len */
+        cmp     _nice_match,%eax        /* len >= nice_match ? */
+        jl      long_loop
+the_end:
+        mov     %ebx,%eax               /* result = eax = best_len */
+       pop     %ebx
+        pop     %esi
+        pop     %edi
+        pop     %ebp
+        ret
+maxmatch:
+        cmpsb
+        jmp     mismatch
+
+#else
+
+/* ======================== 680x0 version ================================= */
+
+#if defined(m68k) || defined(__mc68000__) || defined(__MC68000__)
+#  ifndef mc68000
+#    define mc68000
+#  endif
+#endif
+
+#if (defined(__mc68020__) || defined(__MC68020__)) && !defined(mc68020)
+#  define mc68020
+#endif
+
+#if defined(mc68020) || defined(mc68000)
+
+#if defined(mc68020) && !defined(UNALIGNED_OK)
+#  define UNALIGNED_OK
+#endif
+
+#if defined(m68k) && !defined(NeXT) && !defined(atarist)
+  /* Try 'delta' style */
+
+#  define GLOBAL(symbol)       global  symbol
+#  define TEXT                 text
+#  define FILE(filename)       file    filename
+#  define invert_maybe(src,dst)        dst,src
+#  define imm(data)            &data
+#  define reg(register)                %register
+
+#  define addl                 add.l
+#  define addql                        addq.l
+#  define blos                 blo.b
+#  define bhis                 bhi.b
+#  define bras                 bra.b
+#  define clrl                 clr.l
+#  define cmpmb                        cmpm.b
+#  define cmpw                 cmp.w
+#  define cmpl                 cmp.l
+#  define lslw                 lsl.w
+#  define lsrl                 lsr.l
+#  define movel                        move.l
+#  define movew                        move.w
+#  define moveb                        move.b
+#  define moveml               movem.l
+#  define subl                 sub.l
+#  define subw                 sub.w
+#  define subql                        subq.l
+
+#  define IndBase(bd,An)       (bd,An)
+#  define IndBaseNdxl(bd,An,Xn)        (bd,An,Xn.l)
+#  define IndBaseNdxw(bd,An,Xn)        (bd,An,Xn.w)
+#  define predec(An)           -(An)
+#  define postinc(An)          (An)+
+
+#else /* Motorola style (Sun 3, NeXT, Amiga, Atari) */
+
+#  define GLOBAL(symbol)       .globl  symbol
+#  define TEXT                 .text
+#  define FILE(filename)       .even
+#  define invert_maybe(src,dst)        src,dst
+#  ifdef sun
+#    define imm(data)          #data
+#  else
+#    define imm(data)          \#data
+#  endif
+#  define reg(register)                register
+
+#  define blos                 bcss
+#  ifdef sun
+#    define movel              movl
+#    define movew              movw
+#    define moveb              movb
+#  endif
+#  define IndBase(bd,An)       An@(bd)
+#  define IndBaseNdxl(bd,An,Xn)        An@(bd,Xn:l)
+#  define IndBaseNdxw(bd,An,Xn)        An@(bd,Xn:w)
+#  define predec(An)           An@-
+#  define postinc(An)          An@+
+
+#endif /* styles */
+
+#define Best_Len       reg(d0)         /* unsigned */
+#define Cur_Match      reg(d1)         /* Ipos */
+#define Loop_Counter   reg(d2)         /* int */
+#define Scan_Start     reg(d3)         /* unsigned short */
+#define Scan_End       reg(d4)         /* unsigned short */
+#define Limit          reg(d5)         /* IPos */
+#define Chain_Length   reg(d6)         /* unsigned */
+#define Scan_Test      reg(d7)
+#define Scan           reg(a0)         /* *uch */
+#define Match          reg(a1)         /* *uch */
+#define Prev_Address   reg(a2)         /* *Pos */
+#define Scan_Ini       reg(a3)         /* *uch */
+#define Match_Ini      reg(a4)         /* *uch */
+#define Stack_Pointer  reg(sp)
+
+#define MAX_MATCH      258
+#define MIN_MATCH      3
+#define WSIZE          32768
+#define MAX_DIST       (WSIZE - MAX_MATCH - MIN_MATCH - 1)
+
+       GLOBAL  (_match_init)
+       GLOBAL  (_longest_match)
+
+       TEXT
+
+       FILE    ("match.S")
+
+_match_init:
+       rts
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* int longest_match (cur_match) */
+
+#ifdef UNALIGNED_OK
+#  define pushreg      15928           /* d2-d6/a2-a4 */
+#  define popreg       7292
+#else
+#  define pushreg      16184           /* d2-d7/a2-a4 */
+#  define popreg       7420
+#endif
+
+_longest_match:
+       movel   IndBase(4,Stack_Pointer),Cur_Match
+       moveml  imm(pushreg),predec(Stack_Pointer)
+       movel   _max_chain_length,Chain_Length
+       movel   _prev_length,Best_Len
+       movel   imm(_prev),Prev_Address
+       movel   imm(_window+MIN_MATCH),Match_Ini
+       movel   _strstart,Limit
+       movel   Match_Ini,Scan_Ini
+       addl    Limit,Scan_Ini
+       subw    imm(MAX_DIST),Limit
+       bhis    L__limit_ok
+       clrl    Limit
+L__limit_ok:
+       cmpl    invert_maybe(_good_match,Best_Len)
+       blos    L__length_ok
+       lsrl    imm(2),Chain_Length
+L__length_ok:
+       subql   imm(1),Chain_Length
+#ifdef UNALIGNED_OK
+       movew   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+       movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+       moveb   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+       lslw    imm(8),Scan_Start
+       moveb   IndBase(-MIN_MATCH+1,Scan_Ini),Scan_Start
+       moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+       lslw    imm(8),Scan_End
+       moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+       bras    L__do_scan
+
+L__long_loop:
+#ifdef UNALIGNED_OK
+       movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+       moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+       lslw    imm(8),Scan_End
+       moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+
+L__short_loop:
+       lslw    imm(1),Cur_Match
+       movew   IndBaseNdxl(0,Prev_Address,Cur_Match),Cur_Match
+       cmpw    invert_maybe(Limit,Cur_Match)
+       dbls    Chain_Length,L__do_scan
+       bras    L__return
+
+L__do_scan:
+       movel   Match_Ini,Match
+       addl    Cur_Match,Match
+#ifdef UNALIGNED_OK
+       cmpw    invert_maybe(IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_End)
+       bne     L__short_loop
+       cmpw    invert_maybe(IndBase(-MIN_MATCH,Match),Scan_Start)
+       bne     L__short_loop
+#else
+       moveb   IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_Test
+       lslw    imm(8),Scan_Test
+       moveb   IndBaseNdxw(-MIN_MATCH,Match,Best_Len),Scan_Test
+       cmpw    invert_maybe(Scan_Test,Scan_End)
+       bne     L__short_loop
+       moveb   IndBase(-MIN_MATCH,Match),Scan_Test
+       lslw    imm(8),Scan_Test
+       moveb   IndBase(-MIN_MATCH+1,Match),Scan_Test
+       cmpw    invert_maybe(Scan_Test,Scan_Start)
+       bne     L__short_loop
+#endif
+
+       movew   imm((MAX_MATCH-MIN_MATCH+1)-1),Loop_Counter
+       movel   Scan_Ini,Scan
+L__scan_loop:
+       cmpmb   postinc(Match),postinc(Scan)
+       dbne    Loop_Counter,L__scan_loop
+
+       subl    Scan_Ini,Scan
+       addql   imm(MIN_MATCH-1),Scan
+       cmpl    invert_maybe(Best_Len,Scan)
+       bls     L__short_loop
+       movel   Scan,Best_Len
+       movel   Cur_Match,_match_start
+       cmpl    invert_maybe(_nice_match,Best_Len)
+       blos    L__long_loop
+L__return:
+       moveml  postinc(Stack_Pointer),imm(popreg)
+       rts
+
+#else
+ error: this asm version is for 386 or 680x0 only
+#endif /* mc68000 || mc68020 */
+#endif /* i386 || _I386   */
diff --git a/usr/src/contrib/gzip/revision.h b/usr/src/contrib/gzip/revision.h
new file mode 100644 (file)
index 0000000..354772b
--- /dev/null
@@ -0,0 +1,16 @@
+/* revision.h -- define the version number
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#define VERSION "1.0.7"
+#define PATCHLEVEL 0
+#define REVDATE "18 Mar 93"
+
+/* This version does not support compression into old compress format: */
+#ifdef LZW
+#  undef LZW
+#endif
+
+/* $Id: revision.h,v 0.18 1993/03/18 18:14:56 jloup Exp $ */
diff --git a/usr/src/contrib/gzip/tailor.h b/usr/src/contrib/gzip/tailor.h
new file mode 100644 (file)
index 0000000..667072a
--- /dev/null
@@ -0,0 +1,207 @@
+/* tailor.h -- target dependent definitions
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* The target dependent definitions should be defined here only.
+ * The target dependent functions should be defined in tailor.c.
+ */
+
+/* $Id: tailor.h,v 0.14 1993/03/18 18:14:56 jloup Exp $ */
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+#ifdef MSDOS
+#  ifdef __GNUC__
+     /* DJGPP version 1.09+ on MS-DOS.
+      * The DJGPP 1.09 stat() function must be upgraded before gzip will
+      * fully work.
+      * No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
+      * implies DIRENT.
+      */
+#    define near
+#  else
+#    define MAXSEG_64K
+#    ifdef __TURBOC__
+#      define NO_UTIME
+#    else /* MSC */
+#      define HAVE_SYS_UTIME_H
+#      define NO_UTIME_H
+#    endif
+#  endif
+#  define PATH_SEP2 '\\'
+#  define PATH_SEP3 ':'
+#  define MAX_PATH_LEN  128
+#  define NO_MULTIPLE_DOTS
+#  define MAX_EXT_CHARS 3
+#  define Z_SUFFIX "z"
+#  define NO_CHOWN
+#  define PROTO
+#  define STDC_HEADERS
+#  define NO_SIZE_CHECK
+#  define casemap(c) tolow(c) /* Force file names to lower case */
+#  include <io.h>
+#  define OS_CODE  0x00
+#  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
+#  if !defined(NO_ASM) && !defined(ASMV)
+#    define ASMV
+#  endif
+#else
+#  define near
+#endif
+
+#ifdef OS2
+#  define PATH_SEP2 '\\'
+#  define PATH_SEP3 ':'
+#  define MAX_PATH_LEN  260
+#  ifdef OS2FAT
+#    define NO_MULTIPLE_DOTS
+#    define MAX_EXT_CHARS 3
+#    define Z_SUFFIX "z"
+#  endif
+#  define NO_CHOWN
+#  define PROTO
+#  define STDC_HEADERS
+#  define HAVE_SYS_UTIME_H
+#  define NO_UTIME_H
+#  define DIRENT
+#  define casemap(c) tolow(c)
+#  include <io.h>
+#  define OS_CODE  0x06
+#  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
+#endif
+
+#ifdef __EMX__
+#  define EXPAND(argc,argv) {_response(&argc, &argv); _wildcard(&argc, &argv);}
+#endif
+
+#ifndef MAXSEG_64K
+#  define fcalloc(items,size) malloc((unsigned)(items)*(unsigned)(size))
+#  define fcfree(ptr) free(ptr)
+#else
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#    define DYN_ALLOC
+     /* Turbo C 2.0 does not accept static allocations of large arrays */
+     void * fcalloc (unsigned items, unsigned size);
+     void fcfree (void *ptr);
+#  else /* MSC */
+#    include <malloc.h>
+#    define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
+#    define fcfree(ptr) hfree(ptr)
+#  endif
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define PATH_SEP ']'
+#  define PATH_SEP2 ':'
+#  define SUFFIX_SEP ';'
+#  define NO_MULTIPLE_DOTS
+#  define Z_SUFFIX "-z"
+#  define RECORD_IO 1
+#  define casemap(c) tolow(c)
+#  define OS_CODE  0x02
+#  define OPTIONS_VAR "GZIP_OPT"
+#  define STDC_HEADERS
+#  define NO_UTIME
+#  include <file.h>
+#  ifdef VAXC
+#    define NO_FCNTL_H
+#    define unlink delete
+#    include <unixio.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define PATH_SEP2 ':'
+#  define STDC_HEADERS
+#  define casemap(c) tolow(c) /* Force file names to lower case */
+#  define OS_CODE  0x01
+#  define ASMV
+#  ifdef __GNUC__
+#    define DIRENT
+#    define HAVE_UNISTD_H
+#    define RETSIGTYPE int
+#  else /* SASC */
+#    define NO_STDIN_FSTAT
+#    define SYSDIR
+#    define NO_SYMLINK
+#    define NO_CHOWN
+#    define NO_FCNTL_H
+#    include <fcntl.h> /* for read() and write() */
+#    define direct dirent
+     extern void _expand_args(int *argc, char ***argv);
+#    define EXPAND(argc,argv) _expand_args(&argc,&argv);
+#  endif
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  ifndef STDC_HEADERS
+#    define STDC_HEADERS
+#    define HAVE_UNISTD_H
+#    define DIRENT
+#  endif
+#  define ASMV
+#  define OS_CODE  0x05
+#  ifdef TOSFS
+#    define NO_SYMLINK
+#    define NO_MULTIPLE_DOTS
+#    define MAX_EXT_CHARS 3
+#    define Z_SUFFIX "z"
+#    define NO_CHOWN
+#  endif
+#endif
+
+#ifdef MACOS
+#  define OS_CODE  0x07
+#endif
+
+#ifdef WIN32
+#  define OS_CODE  0x0b
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifndef unix
+#  define NO_PTY /* no pseudo ttys */
+#endif
+
+       /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef PATH_SEP
+#  define PATH_SEP '/'
+#endif
+
+#ifndef casemap
+#  define casemap(c) (c)
+#endif
+
+#ifndef OPTIONS_VAR
+#  define OPTIONS_VAR "GZIP"
+#endif
+
+#ifndef Z_SUFFIX
+#  define Z_SUFFIX ".z"
+#endif
+#define Z_LEN strlen(Z_SUFFIX)
+
+#ifndef EXPAND
+#  define EXPAND(argc,argv)
+#endif
+
+#ifndef RECORD_IO
+#  define RECORD_IO 0
+#endif
+
+#ifndef SET_BINARY_MODE
+#  define SET_BINARY_MODE(fd)
+#endif
diff --git a/usr/src/contrib/gzip/trees.c b/usr/src/contrib/gzip/trees.c
new file mode 100644 (file)
index 0000000..bd1fe63
--- /dev/null
@@ -0,0 +1,1076 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Encode various sets of source values using variable-length
+ *      binary code trees.
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in the ZIP file in a compressed form
+ *      which is itself a Huffman encoding of the lengths of
+ *      all the code strings (in ascending order by source values).
+ *      The actual code strings are reconstructed from the lengths in
+ *      the UNZIP process, as described in the "application note"
+ *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ *  REFERENCES
+ *
+ *      Lynch, Thomas J.
+ *          Data Compression:  Techniques and Applications, pp. 53-55.
+ *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ *  INTERFACE
+ *
+ *      void ct_init (ush *attr, int *methodp)
+ *          Allocate the match buffer, initialize the various tables and save
+ *          the location of the internal file attribute (ascii/binary) and
+ *          method (DEFLATE/STORE)
+ *
+ *      void ct_tally (int dist, int lc);
+ *          Save the match info and tally the frequency counts.
+ *
+ *      long flush_block (char *buf, ulg stored_len, int eof)
+ *          Determine the best encoding for the current block: dynamic trees,
+ *          static trees or store, and output the encoded block to the zip
+ *          file. Returns the total compressed length for the file so far.
+ *
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+#ifndef lint
+static char rcsid[] = "$Id: trees.c,v 0.10 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+
+local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int near extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+#  ifdef SMALL_MEM
+#    define LIT_BUFSIZE  0x2000
+#  else
+#  ifdef MEDIUM_MEM
+#    define LIT_BUFSIZE  0x4000
+#  else
+#    define LIT_BUFSIZE  0x8000
+#  endif
+#  endif
+#endif
+#ifndef DIST_BUFSIZE
+#  define DIST_BUFSIZE  LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances.  There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ *   - frequencies can be kept in 16 bit counters
+ *   - if compression is not successful for the first block, all input data is
+ *     still in the window so we can still emit a stored block even when input
+ *     comes from standard input.  (This can also be done for all blocks if
+ *     LIT_BUFSIZE is not greater than 32K.)
+ *   - if compression is not successful for a file smaller than 64K, we can
+ *     even emit a stored file instead of a stored block (saving 5 bytes).
+ *   - creating new Huffman trees less frequently may not provide fast
+ *     adaptation to changes in the input data statistics. (Take for
+ *     example a binary file with poorly compressible code followed by
+ *     a highly compressible string table.) Smaller buffer sizes give
+ *     fast adaptation but have of course the overhead of transmitting trees
+ *     more frequently.
+ *   - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#if LIT_BUFSIZE > INBUFSIZ
+    error cannot overlay l_buf and inbuf
+#endif
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+/* ===========================================================================
+ * Local data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data near dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+local ct_data near static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data near static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data near bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+    ct_data near *dyn_tree;      /* the dynamic tree */
+    ct_data near *static_tree;   /* corresponding static tree or NULL */
+    int     near *extra_bits;    /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+    int     max_code;            /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc near l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc near d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS, 0};
+
+local tree_desc near bl_desc =
+{bl_tree, (ct_data near *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush near bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local uch near bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len;               /* number of elements in the heap */
+local int heap_max;               /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+local uch near depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local int near base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int near base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#define l_buf inbuf
+/* DECLARE(uch, l_buf, LIT_BUFSIZE);  buffer for literals or lengths */
+
+/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
+
+local uch near flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit;    /* running index in l_buf */
+local unsigned last_dist;   /* running index in d_buf */
+local unsigned last_flags;  /* running index in flag_buf */
+local uch flags;            /* current flags not yet saved in flag_buf */
+local uch flag_bit;         /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len;        /* bit length of current block with optimal trees */
+local ulg static_len;     /* bit length of current block with static trees */
+
+local ulg compressed_len; /* total bit length of compressed file */
+
+local ulg input_len;      /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+
+ush *file_type;        /* pointer to UNKNOWN, BINARY or ASCII */
+int *file_method;      /* pointer to DEFLATE or STORE */
+
+#ifdef DEBUG
+extern ulg bits_sent;  /* bit length of the compressed data */
+extern long isize;     /* byte length of input file */
+#endif
+
+extern long block_start;       /* window offset of current block */
+extern unsigned near strstart; /* window offset of current string */
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block     OF((void));
+local void pqdownheap     OF((ct_data near *tree, int k));
+local void gen_bitlen     OF((tree_desc near *desc));
+local void gen_codes      OF((ct_data near *tree, int max_code));
+local void build_tree     OF((tree_desc near *desc));
+local void scan_tree      OF((ct_data near *tree, int max_code));
+local void send_tree      OF((ct_data near *tree, int max_code));
+local int  build_bl_tree  OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
+local void set_file_type  OF((void));
+
+
+#ifndef DEBUG
+#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(c, tree) \
+     { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, methodp)
+    ush  *attr;   /* pointer to internal file attribute */
+    int  *methodp; /* pointer to compression method */
+{
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+
+    file_type = attr;
+    file_method = methodp;
+    compressed_len = input_len = 0L;
+        
+    if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "ct_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data near *)static_ltree, L_CODES+1);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse(n, 5);
+    }
+
+    /* Initialize the first block of the first file: */
+    init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+    dyn_ltree[END_BLOCK].Freq = 1;
+    opt_len = static_len = 0L;
+    last_lit = last_dist = last_flags = 0;
+    flags = 0; flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+    top = heap[SMALLEST]; \
+    heap[SMALLEST] = heap[heap_len--]; \
+    pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(tree, k)
+    ct_data near *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, heap[j])) break;
+
+        /* Exchange v with the smallest son */
+        heap[k] = heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(desc)
+    tree_desc near *desc; /* the tree descriptor */
+{
+    ct_data near *tree  = desc->dyn_tree;
+    int near *extra     = desc->extra_bits;
+    int base            = desc->extra_base;
+    int max_code        = desc->max_code;
+    int max_length      = desc->max_length;
+    ct_data near *stree = desc->static_tree;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[heap[heap_max]].Len = 0; /* root of the heap */
+
+    for (h = heap_max+1; h < HEAP_SIZE; h++) {
+        n = heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        opt_len += (ulg)f * (bits + xbits);
+        if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (bl_count[bits] == 0) bits--;
+        bl_count[bits]--;      /* move one leaf down the tree */
+        bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = bl_count[bits];
+        while (n != 0) {
+            m = heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code)
+    ct_data near *tree;        /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(desc)
+    tree_desc near *desc; /* the tree descriptor */
+{
+    ct_data near *tree   = desc->dyn_tree;
+    ct_data near *stree  = desc->static_tree;
+    int elems            = desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node = elems;  /* next internal node of the tree */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    heap_len = 0, heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            heap[++heap_len] = max_code = n;
+            depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (heap_len < 2) {
+        int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+        tree[new].Freq = 1;
+        depth[new] = 0;
+        opt_len--; if (stree) static_len -= stree[new].Len;
+        /* new is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    do {
+        pqremove(tree, n);   /* n = node of least frequency */
+        m = heap[SMALLEST];  /* m = node of next least frequency */
+
+        heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+        heap[--heap_max] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        heap[SMALLEST] = node++;
+        pqdownheap(tree, SMALLEST);
+
+    } while (heap_len >= 2);
+
+    heap[--heap_max] = heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen((tree_desc near *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data near *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+    ct_data near *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) bl_tree[curlen].Freq++;
+            bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            bl_tree[REPZ_3_10].Freq++;
+        } else {
+            bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (tree, max_code)
+    ct_data near *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(curlen, bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(curlen, bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+        } else {
+            send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree()
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
+    scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree((tree_desc near *)(&bl_desc));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(lcodes, dcodes, blcodes)
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(dcodes-1,   5);
+    send_bits(blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
+
+    send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
+
+    send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg flush_block(buf, stored_len, eof)
+    char *buf;        /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+     /* Check if the file is ascii or binary */
+    if (*file_type == (ush)UNKNOWN) set_file_type();
+
+    /* Construct the literal and distance trees */
+    build_tree((tree_desc near *)(&l_desc));
+    Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+    build_tree((tree_desc near *)(&d_desc));
+    Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
+    /* At this point, opt_len and static_len are the total bit lengths of
+     * the compressed block data, excluding the tree representations.
+     */
+
+    /* Build the bit length tree for the above two trees, and get the index
+     * in bl_order of the last bit length code to send.
+     */
+    max_blindex = build_bl_tree();
+
+    /* Determine the best encoding. Compute first the block length in bytes */
+    opt_lenb = (opt_len+3+7)>>3;
+    static_lenb = (static_len+3+7)>>3;
+    input_len += stored_len; /* for debugging only */
+
+    Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+            opt_lenb, opt_len, static_lenb, static_len, stored_len,
+            last_lit, last_dist));
+
+    if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    /* If compression failed and this is the first and last block,
+     * and if the zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef FORCE_METHOD
+    if (level == 1 && eof && compressed_len == 0L) { /* force stored file */
+#else
+    if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
+#endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (char*)0) error ("block vanished");
+
+        copy_block(buf, (unsigned)stored_len, 0); /* without header */
+        compressed_len = stored_len << 3;
+        *file_method = STORED;
+
+#ifdef FORCE_METHOD
+    } else if (level == 2 && buf != (char*)0) { /* force stored block */
+#else
+    } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        send_bits((STORED_BLOCK<<1)+eof, 3);  /* send block type */
+        compressed_len = (compressed_len + 3 + 7) & ~7L;
+        compressed_len += (stored_len + 4) << 3;
+
+        copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+    } else if (level == 3) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits((STATIC_TREES<<1)+eof, 3);
+        compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
+        compressed_len += 3 + static_len;
+    } else {
+        send_bits((DYN_TREES<<1)+eof, 3);
+        send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+        compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
+        compressed_len += 3 + opt_len;
+    }
+    Assert (compressed_len == bits_sent, "bad compressed size");
+    init_block();
+
+    if (eof) {
+        Assert (input_len == isize, "bad input size");
+        bi_windup();
+        compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
+           compressed_len-7*eof));
+
+    return compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+    int dist;  /* distance of matched string */
+    int lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    l_buf[last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        dyn_ltree[lc].Freq++;
+    } else {
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
+
+        dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        dyn_dtree[d_code(dist)].Freq++;
+
+        d_buf[last_dist++] = (ush)dist;
+        flags |= flag_bit;
+    }
+    flag_bit <<= 1;
+
+    /* Output the flags if they fill a byte: */
+    if ((last_lit & 7) == 0) {
+        flag_buf[last_flags++] = flags;
+        flags = 0, flag_bit = 1;
+    }
+    /* Try to guess if it is profitable to stop the current block here */
+    if (level > 2 && (last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)last_lit*8L;
+        ulg in_length = (ulg)strstart-block_start;
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+               last_lit, last_dist, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+    /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(ltree, dtree)
+    ct_data near *ltree; /* literal tree */
+    ct_data near *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned dx = 0;    /* running index in d_buf */
+    unsigned fx = 0;    /* running index in flag_buf */
+    uch flag = 0;       /* current flags */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (last_lit != 0) do {
+        if ((lx & 7) == 0) flag = flag_buf[fx++];
+        lc = l_buf[lx++];
+        if ((flag & 1) == 0) {
+            send_code(lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(lc, extra);        /* send the extra length bits */
+            }
+            dist = d_buf[dx++];
+            /* Here, dist is the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+        flag >>= 1;
+    } while (lx < last_lit);
+
+    send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_file_type()
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
+    *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
+    if (*file_type == BINARY && translate_eol) {
+        warn("-l used on binary file", "");
+    }
+}
diff --git a/usr/src/contrib/gzip/unlzw.c b/usr/src/contrib/gzip/unlzw.c
new file mode 100644 (file)
index 0000000..159b20a
--- /dev/null
@@ -0,0 +1,365 @@
+/* unlzw.c -- decompress files in LZW format.
+ * The code in this file is directly derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * This is a temporary version which will be rewritten in some future version
+ * to accommodate in-memory decompression.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: unlzw.c,v 0.12 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "lzw.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif
+
+typedef        unsigned char   char_type;
+typedef          long   code_int;
+typedef unsigned long  count_int;
+typedef unsigned short count_short;
+typedef unsigned long  cmp_code_int;
+
+#define MAXCODE(n)     (1L << (n))
+    
+#ifndef        REGISTERS
+#      define  REGISTERS       2
+#endif
+#define        REG1    
+#define        REG2    
+#define        REG3    
+#define        REG4    
+#define        REG5    
+#define        REG6    
+#define        REG7    
+#define        REG8    
+#define        REG9    
+#define        REG10
+#define        REG11   
+#define        REG12   
+#define        REG13
+#define        REG14
+#define        REG15
+#define        REG16
+#if REGISTERS >= 1
+#      undef   REG1
+#      define  REG1    register
+#endif
+#if REGISTERS >= 2
+#      undef   REG2
+#      define  REG2    register
+#endif
+#if REGISTERS >= 3
+#      undef   REG3
+#      define  REG3    register
+#endif
+#if REGISTERS >= 4
+#      undef   REG4
+#      define  REG4    register
+#endif
+#if REGISTERS >= 5
+#      undef   REG5
+#      define  REG5    register
+#endif
+#if REGISTERS >= 6
+#      undef   REG6
+#      define  REG6    register
+#endif
+#if REGISTERS >= 7
+#      undef   REG7
+#      define  REG7    register
+#endif
+#if REGISTERS >= 8
+#      undef   REG8
+#      define  REG8    register
+#endif
+#if REGISTERS >= 9
+#      undef   REG9
+#      define  REG9    register
+#endif
+#if REGISTERS >= 10
+#      undef   REG10
+#      define  REG10   register
+#endif
+#if REGISTERS >= 11
+#      undef   REG11
+#      define  REG11   register
+#endif
+#if REGISTERS >= 12
+#      undef   REG12
+#      define  REG12   register
+#endif
+#if REGISTERS >= 13
+#      undef   REG13
+#      define  REG13   register
+#endif
+#if REGISTERS >= 14
+#      undef   REG14
+#      define  REG14   register
+#endif
+#if REGISTERS >= 15
+#      undef   REG15
+#      define  REG15   register
+#endif
+#if REGISTERS >= 16
+#      undef   REG16
+#      define  REG16   register
+#endif
+    
+#ifndef        BYTEORDER
+#      define  BYTEORDER       0000
+#endif
+       
+#ifndef        NOALLIGN
+#      define  NOALLIGN        0
+#endif
+
+
+union  bytes {
+    long  word;
+    struct {
+#if BYTEORDER == 4321
+       char_type       b1;
+       char_type       b2;
+       char_type       b3;
+       char_type       b4;
+#else
+#if BYTEORDER == 1234
+       char_type       b4;
+       char_type       b3;
+       char_type       b2;
+       char_type       b1;
+#else
+#      undef   BYTEORDER
+       int  dummy;
+#endif
+#endif
+    } bytes;
+};
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+#  define input(b,o,c,n,m){ \
+     (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
+     (o) += (n); \
+   }
+#else
+#  define input(b,o,c,n,m){ \
+     REG1 char_type *p = &(b)[(o)>>3]; \
+     (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
+     ((long)(p[2])<<16))>>((o)&0x7))&(m); \
+     (o) += (n); \
+   }
+#endif
+
+#ifndef MAXSEG_64K
+   /* DECLARE(ush, tab_prefix, (1<<BITS)); -- prefix code */
+#  define tab_prefixof(i) tab_prefix[i]
+#  define clear_tab_prefixof() memzero(tab_prefix, 256);
+#else
+   /* DECLARE(ush, tab_prefix0, (1<<(BITS-1)); -- prefix for even codes */
+   /* DECLARE(ush, tab_prefix1, (1<<(BITS-1)); -- prefix for odd  codes */
+   ush *tab_prefix[2];
+#  define tab_prefixof(i) tab_prefix[(i)&1][(i)>>1]
+#  define clear_tab_prefixof() \
+      memzero(tab_prefix0, 128), \
+      memzero(tab_prefix1, 128);
+#endif
+#define de_stack        ((char_type *)(&d_buf[DIST_BUFSIZE-1]))
+#define tab_suffixof(i) tab_suffix[i]
+
+int block_mode = BLOCK_MODE; /* block compress mode -C compatible with 2.0 */
+
+/* ============================================================================
+ * Decompress in to out.  This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets iptr to insize-1 included.
+ *   The magic header has already been checked and skipped.
+ *   bytes_in and bytes_out have been initialized.
+ */
+void unlzw(in, out) 
+    int in, out;    /* input and output file descriptors */
+{
+    REG2   char_type  *stackp;
+    REG3   code_int   code;
+    REG4   int        finchar;
+    REG5   code_int   oldcode;
+    REG6   code_int   incode;
+    REG7   long       inbits;
+    REG8   long       posbits;
+    REG9   int        outpos;
+/*  REG10  int        insize; (global) */
+    REG11  unsigned   bitmask;
+    REG12  code_int   free_ent;
+    REG13  code_int   maxcode;
+    REG14  code_int   maxmaxcode;
+    REG15  int        n_bits;
+    REG16  int        rsize;
+    
+#ifdef MAXSEG_64K
+    tab_prefix[0] = tab_prefix0;
+    tab_prefix[1] = tab_prefix1;
+#endif
+    maxbits = get_byte();
+    block_mode = maxbits & BLOCK_MODE;
+    if ((maxbits & LZW_RESERVED) != 0) {
+       WARN((stderr, "%s: %s: warning, unknown flags 0x%x\n",
+             progname, ifname, maxbits & LZW_RESERVED));
+    }
+    maxbits &= BIT_MASK;
+    maxmaxcode = MAXCODE(maxbits);
+    
+    if (maxbits > BITS) {
+       fprintf(stderr,
+               "%s: %s: compressed with %d bits, can only handle %d bits\n",
+               progname, ifname, maxbits, BITS);
+       exit_code = ERROR;
+       return;
+    }
+    rsize = insize;
+    maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+    bitmask = (1<<n_bits)-1;
+    oldcode = -1;
+    finchar = 0;
+    outpos = 0;
+    posbits = inptr<<3;
+
+    free_ent = ((block_mode) ? FIRST : 256);
+    
+    clear_tab_prefixof(); /* Initialize the first 256 entries in the table. */
+    
+    for (code = 255 ; code >= 0 ; --code) {
+       tab_suffixof(code) = (char_type)code;
+    }
+    do {
+       REG1 int i;
+       int  e;
+       int  o;
+       
+    resetbuf:
+       e = insize-(o = (posbits>>3));
+       
+       for (i = 0 ; i < e ; ++i) {
+           inbuf[i] = inbuf[i+o];
+       }
+       insize = e;
+       posbits = 0;
+       
+       if (insize < INBUF_EXTRA) {
+           if ((rsize = read(in, inbuf+insize, INBUFSIZ)) == EOF) {
+               read_error();
+           }
+           insize += rsize;
+       }
+       inbits = ((rsize != 0) ? ((long)insize - insize%n_bits)<<3 : 
+                 ((long)insize<<3)-(n_bits-1));
+       
+       while (inbits > posbits) {
+           if (free_ent > maxcode) {
+               posbits = ((posbits-1) +
+                          ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+               ++n_bits;
+               if (n_bits == maxbits) {
+                   maxcode = maxmaxcode;
+               } else {
+                   maxcode = MAXCODE(n_bits)-1;
+               }
+               bitmask = (1<<n_bits)-1;
+               goto resetbuf;
+           }
+           input(inbuf,posbits,code,n_bits,bitmask);
+           
+           if (oldcode == -1) {
+               outbuf[outpos++] = (char_type)(finchar = (int)(oldcode=code));
+               continue;
+           }
+           if (code == CLEAR && block_mode) {
+               clear_tab_prefixof();
+               free_ent = FIRST - 1;
+               posbits = ((posbits-1) +
+                          ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+               maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+               bitmask = (1<<n_bits)-1;
+               goto resetbuf;
+           }
+           incode = code;
+           stackp = de_stack;
+           
+           if (code >= free_ent) { /* Special case for KwKwK string. */
+               if (code > free_ent) {
+
+                   REG1 char_type *p;
+
+                   posbits -= n_bits;
+                   p = &inbuf[posbits>>3];
+#ifdef DEBUG               
+                   fprintf(stderr,
+                           "code:%ld free_ent:%ld n_bits:%d insize:%u\n",
+                           code, free_ent, n_bits, insize);
+                   fprintf(stderr,
+                           "posbits:%ld inbuf:%02X %02X %02X %02X %02X\n",
+                           posbits, p[-1],p[0],p[1],p[2],p[3]);
+#endif
+                   if (!test && outpos > 0) {
+                       write_buf(out, outbuf, outpos);
+                   }
+                   error("corrupt input. Use zcat to recover some data.");
+               }
+               *--stackp = (char_type)finchar;
+               code = oldcode;
+           }
+
+           while ((cmp_code_int)code >= (cmp_code_int)256) {
+               /* Generate output characters in reverse order */
+               *--stackp = tab_suffixof(code);
+               code = tab_prefixof(code);
+           }
+           *--stackp = (char_type)(finchar = tab_suffixof(code));
+           
+           /* And put them out in forward order */
+           {
+               REG1 int        i;
+           
+               if (outpos+(i = (de_stack-stackp)) >= OUTBUFSIZ) {
+                   do {
+                       if (i > OUTBUFSIZ-outpos) i = OUTBUFSIZ-outpos;
+
+                       if (i > 0) {
+                           memcpy(outbuf+outpos, stackp, i);
+                           outpos += i;
+                       }
+                       if (outpos >= OUTBUFSIZ) {
+                           if (!test) write_buf(out, outbuf, outpos);
+                           outpos = 0;
+                       }
+                       stackp+= i;
+                   } while ((i = (de_stack-stackp)) > 0);
+               } else {
+                   memcpy(outbuf+outpos, stackp, i);
+                   outpos += i;
+               }
+           }
+
+           if ((code = free_ent) < maxmaxcode) { /* Generate the new entry. */
+
+               tab_prefixof(code) = (unsigned short)oldcode;
+               tab_suffixof(code) = (char_type)finchar;
+               free_ent = code+1;
+           } 
+           oldcode = incode;   /* Remember previous code.      */
+       }
+       bytes_in += rsize;
+
+    } while (rsize != 0);
+    
+    if (!test && outpos > 0) write_buf(out, outbuf, outpos);
+}
diff --git a/usr/src/contrib/gzip/unpack.c b/usr/src/contrib/gzip/unpack.c
new file mode 100644 (file)
index 0000000..f1ff93f
--- /dev/null
@@ -0,0 +1,238 @@
+/* unpack.c -- decompress files in pack format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: unpack.c,v 1.2 1993/02/04 13:21:06 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#include <stdio.h>
+
+#define MIN(a,b) ((a) <= (b) ? (a) : (b))
+/* The arguments must not have side effects. */
+
+#define MAX_BITLEN 25
+/* Maximum length of Huffman codes. (Minor modifications to the code
+ * would be needed to support 32 bits codes, but pack never generates
+ * more than 24 bits anyway.)
+ */
+
+#define LITERALS 256
+/* Number of literals, excluding the End of Block (EOB) code */
+
+#define MAX_PEEK 12
+/* Maximum number of 'peek' bits used to optimize traversal of the
+ * Huffman tree.
+ */
+
+local ulg orig_len;       /* original uncompressed length */
+local int max_len;        /* maximum bit length of Huffman codes */
+
+local uch literal[LITERALS];
+/* The literal bytes present in the Huffman tree. The EOB code is not
+ * represented.
+ */
+
+local int lit_base[MAX_BITLEN+1];
+/* All literals of a given bit length are contiguous in literal[] and
+ * have contiguous codes. literal[code+lit_base[len]] is the literal
+ * for a code of len bits.
+ */
+
+local int leaves [MAX_BITLEN+1]; /* Number of leaves for each bit length */
+local int parents[MAX_BITLEN+1]; /* Number of parents for each bit length */
+
+local int peek_bits; /* Number of peek bits currently used */
+
+local uch prefix_len[1 << MAX_PEEK];
+/* For each bit pattern b of peek_bits bits, prefix_len[b] is the length
+ * of the Huffman code starting with a prefix of b (upper bits), or 0
+ * if all codes of prefix b have more than peek_bits bits. It is not
+ * necessary to have a huge table (large MAX_PEEK) because most of the
+ * codes encountered in the input stream are short codes (by construction).
+ * So for most codes a single lookup will be necessary.
+ */
+
+local ulg bitbuf;
+/* Bits are added on the low part of bitbuf and read from the high part. */
+
+local int valid;                  /* number of valid bits in bitbuf */
+/* all bits above the last valid bit are always zero */
+
+/* Set code to the next 'bits' input bits without skipping them. code
+ * must be the name of a simple variable and bits must not have side effects.
+ * IN assertions: bits <= 25 (so that we still have room for an extra byte
+ * when valid is only 24), and mask = (1<<bits)-1.
+ */
+#define look_bits(code,bits,mask) \
+{ \
+  while (valid < (bits)) bitbuf = (bitbuf<<8) | (ulg)get_byte(), valid += 8; \
+  code = (bitbuf >> (valid-(bits))) & (mask); \
+}
+
+/* Skip the given number of bits (after having peeked at them): */
+#define skip_bits(bits)  (valid -= (bits))
+
+#define clear_bitbuf() (valid = 0, bitbuf = 0)
+
+/* Local functions */
+
+local void read_tree  OF((void));
+local void build_tree OF((void));
+
+/* ===========================================================================
+ * Read the Huffman tree.
+ */
+local void read_tree()
+{
+    int len;  /* bit length */
+    int base; /* base offset for a sequence of leaves */
+    int n;
+
+    /* Read the original input size, MSB first */
+    orig_len = 0;
+    for (n = 1; n <= 4; n++) orig_len = (orig_len << 8) | (ulg)get_byte();
+
+    max_len = (int)get_byte(); /* maximum bit length of Huffman codes */
+    if (max_len > MAX_BITLEN) {
+       error("invalid compressed data -- Huffman code > 32 bits");
+    }
+
+    /* Get the number of leaves at each bit length */
+    n = 0;
+    for (len = 1; len <= max_len; len++) {
+       leaves[len] = (int)get_byte();
+       n += leaves[len];
+    }
+    if (n > LITERALS) {
+       error("too many leaves in Huffman tree");
+    }
+    Trace((stderr, "orig_len %ld, max_len %d, leaves %d\n",
+          orig_len, max_len, n));
+    /* There are at least 2 and at most 256 leaves of length max_len.
+     * (Pack arbitrarily rejects empty files and files consisting of
+     * a single byte even repeated.) To fit the last leaf count in a
+     * byte, it is offset by 2. However, the last literal is the EOB
+     * code, and is not transmitted explicitly in the tree, so we must
+     * adjust here by one only.
+     */
+    leaves[max_len]++;
+
+    /* Now read the leaves themselves */
+    base = 0;
+    for (len = 1; len <= max_len; len++) {
+       /* Remember where the literals of this length start in literal[] : */
+       lit_base[len] = base;
+       /* And read the literals: */
+       for (n = leaves[len]; n > 0; n--) {
+           literal[base++] = (uch)get_byte();
+       }
+    }
+    leaves[max_len]++; /* Now include the EOB code in the Huffman tree */
+}
+
+/* ===========================================================================
+ * Build the Huffman tree and the prefix table.
+ */
+local void build_tree()
+{
+    int nodes = 0; /* number of nodes (parents+leaves) at current bit length */
+    int len;       /* current bit length */
+    uch *prefixp;  /* pointer in prefix_len */
+
+    for (len = max_len; len >= 1; len--) {
+       /* The number of parent nodes at this level is half the total
+        * number of nodes at parent level:
+        */
+       nodes >>= 1;
+       parents[len] = nodes;
+       /* Update lit_base by the appropriate bias to skip the parent nodes
+        * (which are not represented in the literal array):
+        */
+       lit_base[len] -= nodes;
+       /* Restore nodes to be parents+leaves: */
+       nodes += leaves[len];
+    }
+    /* Construct the prefix table, from shortest leaves to longest ones.
+     * The shortest code is all ones, so we start at the end of the table.
+     */
+    peek_bits = MIN(max_len, MAX_PEEK);
+    prefixp = &prefix_len[1<<peek_bits];
+    for (len = 1; len <= peek_bits; len++) {
+       int prefixes = leaves[len] << (peek_bits-len); /* may be 0 */
+       while (prefixes--) *--prefixp = (uch)len;
+    }
+    /* The length of all other codes is unknown: */
+    while (prefixp > prefix_len) *--prefixp = 0;
+}
+
+/* ===========================================================================
+ * Unpack in to out.  This routine does not support the old pack format
+ * with magic header \037\037.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets inptr to insize-1 included.
+ *   The magic header has already been checked. The output buffer is cleared.
+ */
+void unpack(in, out)
+    int in, out;            /* input and output file descriptors */
+{
+    int len;                /* Bit length of current code */
+    unsigned eob;           /* End Of Block code */
+    register unsigned peek; /* lookahead bits */
+    unsigned peek_mask;     /* Mask for peek_bits bits */
+
+    ifd = in;
+    ofd = out;
+
+    read_tree();     /* Read the Huffman tree */
+    build_tree();    /* Build the prefix table */
+    clear_bitbuf();  /* Initialize bit input */
+    peek_mask = (1<<peek_bits)-1;
+
+    /* The eob code is the largest code among all leaves of maximal length: */
+    eob = leaves[max_len]-1;
+    Trace((stderr, "eob %d %x\n", max_len, eob));
+
+    /* Decode the input data: */
+    for (;;) {
+       /* Since eob is the longest code and not shorter than max_len,
+         * we can peek at max_len bits without having the risk of reading
+         * beyond the end of file.
+        */
+       look_bits(peek, peek_bits, peek_mask);
+       len = prefix_len[peek];
+       if (len > 0) {
+           peek >>= peek_bits - len; /* discard the extra bits */
+       } else {
+           /* Code of more than peek_bits bits, we must traverse the tree */
+           ulg mask = peek_mask;
+           len = peek_bits;
+           do {
+                len++, mask = (mask<<1)+1;
+               look_bits(peek, len, mask);
+           } while (peek < parents[len]);
+           /* loop as long as peek is a parent node */
+       }
+       /* At this point, peek is the next complete code, of len bits */
+       if (peek == eob && len == max_len) break; /* end of file? */
+       put_char(literal[peek+lit_base[len]]);
+       Tracev((stderr,"%02d %04x %c\n", len, peek,
+               literal[peek+lit_base[len]]));
+       skip_bits(len);
+    } /* for (;;) */
+
+    flush_window();
+    Trace((stderr, "bytes_out %ld\n", bytes_out));
+    if (orig_len != bytes_out) {
+       error("invalid compressed data--length error");
+    }
+}
+
+
diff --git a/usr/src/contrib/gzip/unzip.c b/usr/src/contrib/gzip/unzip.c
new file mode 100644 (file)
index 0000000..73abc90
--- /dev/null
@@ -0,0 +1,186 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+   This version can extract files in gzip or pkzip format.
+   For the latter, only the first entry is extracted, and it has to be
+   either deflated or stored.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: unzip.c,v 0.11 1993/03/04 19:15:33 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#include <stdio.h>
+
+/* PKZIP header definitions */
+#define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
+#define LOCFLG 6                /* offset of bit flag */
+#define  CRPFLG 1               /*  bit for encrypted entry */
+#define  EXTFLG 8               /*  bit for extended local header */
+#define LOCHOW 8                /* offset of compression method */
+#define LOCTIM 10               /* file mod time (for decryption) */
+#define LOCCRC 14               /* offset of crc */
+#define LOCSIZ 18               /* offset of compressed size */
+#define LOCLEN 22               /* offset of uncompressed length */
+#define LOCFIL 26               /* offset of file name field length */
+#define LOCEXT 28               /* offset of extra field length */
+#define LOCHDR 30               /* size of local header, including sig */
+#define EXTHDR 16               /* size of extended local header, inc sig */
+
+
+/* Globals */
+
+int decrypt;      /* flag to turn on decryption */
+char *key;        /* not used--needed to link crypt.c */
+int pkzip = 0;    /* set for a pkzip file */
+int extended = 0; /* set if extended local header */
+
+/* ===========================================================================
+ * Check zip file and advance inptr to the start of the compressed data.
+ * Get ofname from the local header if necessary.
+ */
+int check_zipfile(in)
+    int in;   /* input file descriptors */
+{
+    uch *h = inbuf + inptr; /* first local header */
+
+    ifd = in;
+
+    /* Check validity of local header, and skip name and extra fields */
+    inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
+
+    if (inptr > insize || LG(h) != LOCSIG) {
+       error("input not a zip file or empty");
+    }
+    method = h[LOCHOW];
+    if (method != STORED && method != DEFLATED) {
+       error("first entry not deflated or stored -- use unzip");
+    }
+
+    /* If entry encrypted, decrypt and validate encryption header */
+    if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
+       fprintf(stderr, "encrypted file, not yet supported.\n");
+       exit_code = ERROR;
+       return -1;
+    }
+
+    /* Save flags for unzip() */
+    extended = (h[LOCFLG] & EXTFLG) != 0;
+    pkzip = 1;
+
+    /* Get ofname and time stamp from local header (to be done) */
+    return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out.  This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets inptr to insize-1 included.
+ *   The magic header has already been checked. The output buffer is cleared.
+ */
+void unzip(in, out)
+    int in, out;   /* input and output file descriptors */
+{
+    ulg orig_crc = 0;       /* original crc */
+    ulg orig_len = 0;       /* original uncompressed length */
+    int n;
+    uch buf[EXTHDR];        /* extended local header */
+
+    ifd = in;
+    ofd = out;
+
+    updcrc(NULL, 0);           /* initialize crc */
+
+    if (pkzip && !extended) {  /* crc and length at the end otherwise */
+       orig_crc = LG(inbuf + LOCCRC);
+       orig_len = LG(inbuf + LOCLEN);
+    }
+
+    /* Decompress */
+    if (method == DEFLATED)  {
+
+       int res = inflate();
+
+       if (res == 3) {
+           error("out of memory");
+       } else if (res != 0) {
+           error("invalid compressed data--format violated");
+       }
+
+    } else if (pkzip && method == STORED) {
+
+       register ulg n = LG(inbuf + LOCLEN);
+
+       if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
+
+           fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ));
+           error("invalid compressed data--length mismatch");
+       }
+       while (n--) {
+           uch c = (uch)get_byte();
+#ifdef CRYPT
+           if (decrypt) zdecode(c);
+#endif
+           put_char(c);
+       }
+       flush_window();
+    } else {
+       error("internal error, invalid method");
+    }
+
+    /* Get the crc and original length */
+    if (!pkzip) {
+        /* crc32  (see algorithm.doc)
+        * uncompressed input size modulo 2^32
+         */
+       for (n = 0; n < 8; n++) {
+           buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+       }
+       orig_crc = LG(buf);
+       orig_len = LG(buf+4);
+
+    } else if (extended) {  /* If extended header, check it */
+       /* signature - 4bytes: 0x50 0x4b 0x07 0x08
+        * CRC-32 value
+         * compressed size 4-bytes
+         * uncompressed size 4-bytes
+        */
+       for (n = 0; n < EXTHDR; n++) {
+           buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+       }
+       orig_crc = LG(buf+4);
+       orig_len = LG(buf+12);
+    }
+
+    /* Validate decompression */
+    if (orig_crc != updcrc(outbuf, 0)) {
+       error("invalid compressed data--crc error");
+    }
+    if (orig_len != bytes_out) {
+       error("invalid compressed data--length error");
+    }
+
+    /* Check if there are more entries in a pkzip file */
+    if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
+       if (to_stdout) {
+           fprintf(stderr,
+                 "warning: zip file has more than one entry--rest ignored\n");
+       } else {
+           /* Don't destroy the input zip file */
+           error("zip file has more than one entry");
+       }
+    }
+    extended = pkzip = 0; /* for next file */
+}
diff --git a/usr/src/contrib/gzip/util.c b/usr/src/contrib/gzip/util.c
new file mode 100644 (file)
index 0000000..d5e3cf5
--- /dev/null
@@ -0,0 +1,414 @@
+/* util.c -- utility functions for gzip support
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: util.c,v 0.13 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+#  include <stdlib.h>
+#else
+   extern int errno;
+#endif
+
+extern ulg crc_32_tab[];   /* crc table, defined below */
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+    uch *s;                 /* pointer to bytes to pump through */
+    unsigned n;             /* number of bytes in s[] */
+{
+    register ulg c;         /* temporary variable */
+
+    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+    if (s == NULL) {
+       c = 0xffffffffL;
+    } else {
+       c = crc;
+       while (n--) {
+           c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+       }
+    }
+    crc = c;
+    return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+    outcnt = 0;
+    insize = inptr = 0;
+    bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+int fill_inbuf()
+{
+    int len;
+
+    /* Read as much as possible */
+    insize = 0;
+    do {
+       len = read(ifd, inbuf+insize, INBUFSIZ-insize);
+        if (len == 0 || len == EOF) break;
+       insize += len;
+    } while (insize < INBUFSIZ);
+
+    if (insize == 0) {
+       read_error();
+    }
+    bytes_in += (ulg)insize;
+    inptr = 1;
+    return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+void flush_outbuf()
+{
+    if (outcnt == 0) return;
+
+    write_buf(ofd, (char *)outbuf, outcnt);
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+    if (outcnt == 0) return;
+    updcrc(window, outcnt);
+
+    if (!test) {
+       write_buf(ofd, (char *)window, outcnt);
+    }
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ */
+void write_buf(fd, buf, cnt)
+    int       fd;
+    voidp     buf;
+    unsigned  cnt;
+{
+    unsigned  n;
+
+    while ((n = write(fd, buf, cnt)) != cnt) {
+       if (n == (unsigned)(-1)) {
+           write_error();
+       }
+       cnt -= n;
+       buf = (voidp)((char*)buf+n);
+    }
+}
+
+/* ========================================================================
+ * Put string s in lower case, return s.
+ */
+char *strlwr(s)
+    char *s;
+{
+    char *t;
+    for (t = s; *t; t++) *t = tolow(*t);
+    return s;
+}
+
+/* ========================================================================
+ * Return the base name of a file (remove any directory prefix and
+ * any version suffix). For systems with filenames that are not
+ * case sensitive, force the base name to lower case.
+ */
+char *basename(fname)
+    char *fname;
+{
+    char *p;
+
+    if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
+#ifdef PATH_SEP2
+    if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
+#endif
+#ifdef PATH_SEP3
+    if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
+#endif
+#ifdef SUFFIX_SEP
+    if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
+#endif
+    if (casemap('A') == 'a') strlwr(fname);
+    return fname;
+}
+
+#if defined(NO_STRING_H) && !defined(STDC_HEADERS)
+
+/* Provide missing strspn and strcspn functions. */
+
+#  ifndef __STDC__
+#    define const
+#  endif
+
+int strspn  OF((const char *s, const char *accept));
+int strcspn OF((const char *s, const char *reject));
+
+/* ========================================================================
+ * Return the length of the maximum initial segment
+ * of s which contains only characters in accept.
+ */
+int strspn(s, accept)
+    const char *s;
+    const char *accept;
+{
+    register const char *p;
+    register const char *a;
+    register int count = 0;
+
+    for (p = s; *p != '\0'; ++p) {
+       for (a = accept; *a != '\0'; ++a) {
+           if (*p == *a) break;
+       }
+       if (*a == '\0') return count;
+       ++count;
+    }
+    return count;
+}
+
+/* ========================================================================
+ * Return the length of the maximum inital segment of s
+ * which contains no characters from reject.
+ */
+int strcspn(s, reject)
+    const char *s;
+    const char *reject;
+{
+    register int count = 0;
+
+    while (*s != '\0') {
+       if (strchr(reject, *s++) != NULL) return count;
+       ++count;
+    }
+    return count;
+}
+
+#endif /* NO_STRING_H */
+
+/* ========================================================================
+ * Add an environment variable (if any) before argv, and update argc.
+ * Return the expanded environment variable to be freed later, or NULL 
+ * if no options were added to argv.
+ */
+#define SEPARATOR      " \t"   /* separators in env variable */
+
+char *add_envopt(argcp, argvp, env)
+    int *argcp;          /* pointer to argc */
+    char ***argvp;       /* pointer to argv */
+    char *env;           /* name of environment variable */
+{
+    char *p;             /* running pointer through env variable */
+    char **oargv;        /* runs through old argv array */
+    char **nargv;        /* runs through new argv array */
+    int         oargc = *argcp; /* old argc */
+    int  nargc = 0;      /* number of arguments in env variable */
+
+    env = (char*)getenv(env);
+    if (env == NULL) return NULL;
+
+    p = (char*)xmalloc(strlen(env)+1);
+    env = strcpy(p, env);                    /* keep env variable intact */
+
+    for (p = env; *p; nargc++ ) {            /* move through env */
+       p += strspn(p, SEPARATOR);           /* skip leading separators */
+       if (*p == '\0') break;
+
+       p += strcspn(p, SEPARATOR);          /* find end of word */
+       if (*p) *p++ = '\0';                 /* mark it */
+    }
+    if (nargc == 0) {
+       free(env); env = NULL;
+       return NULL;
+    }
+    *argcp += nargc;
+    /* Allocate the new argv array, with an extra element just in case
+     * the original arg list did not end with a NULL.
+     */
+    nargv = (char**)calloc(*argcp+1, sizeof(char *));
+    if (nargv == NULL) error("out of memory");
+    oargv  = *argvp;
+    *argvp = nargv;
+
+    /* Copy the program name first */
+    if (oargc-- < 0) error("argc<=0");
+    *(nargv++) = *(oargv++);
+
+    /* Then copy the environment args */
+    for (p = env; nargc > 0; nargc--) {
+       p += strspn(p, SEPARATOR);           /* skip separators */
+       *(nargv++) = p;                      /* store start */
+       while (*p++) ;                       /* skip over word */
+    }
+
+    /* Finally copy the old args and add a NULL (usual convention) */
+    while (oargc--) *(nargv++) = *(oargv++);
+    *nargv = NULL;
+    return env;
+}
+
+/* ========================================================================
+ * Error handlers.
+ */
+void error(m)
+    char *m;
+{
+    fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
+    abort_gzip();
+}
+
+void warn(a, b)
+    char *a, *b;            /* message strings juxtaposed in output */
+{
+    WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
+}
+
+void read_error()
+{
+    fprintf(stderr, "\n%s: ", progname);
+    if (errno != 0) {
+       perror(ifname);
+    } else {
+       fprintf(stderr, "%s: unexpected end of file\n", ifname);
+    }
+    abort_gzip();
+}
+
+void write_error()
+{
+    fprintf(stderr, "\n%s: ", progname);
+    perror(ofname);
+    abort_gzip();
+}
+
+/* ========================================================================
+ * Display compression ratio on stderr.
+ */
+void display_ratio(num, den)
+    long num;
+    long den;
+{
+    long ratio;  /* 1000 times the compression ratio */
+
+    if (den == 0) {
+       ratio = 0; /* no compression */
+    } else if (den < 2147483L) { /* (2**31 -1)/1000 */
+       ratio = 1000L*num/den;
+    } else {
+       ratio = num/(den/1000L);
+    }
+    if (ratio < 0) {
+       putc('-', stderr);
+       ratio = -ratio;
+    }
+    fprintf(stderr, "%2ld.%ld%%", ratio / 10L, ratio % 10L);
+}
+
+
+/* ========================================================================
+ * Semi-safe malloc -- never returns NULL.
+ */
+voidp xmalloc (size)
+    unsigned size;
+{
+    voidp cp = (voidp)malloc (size);
+
+    if (cp == NULL) error("out of memory");
+    return cp;
+}
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by makecrc.c)
+ */
+ulg crc_32_tab[] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
diff --git a/usr/src/contrib/gzip/zcmp b/usr/src/contrib/gzip/zcmp
new file mode 100644 (file)
index 0000000..ac3cf90
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+OPTIONS=
+FILES=
+for ARG
+do
+       case "$ARG" in
+       -*)     OPTIONS="$OPTIONS $ARG";;
+       *)      FILES="$FILES $ARG";;
+       esac
+done
+if test -z "$FILES"; then
+       echo "Usage: zcmp [cmp_options] file [file]"
+       exit 1
+fi
+set $FILES
+if test $# -eq 1; then
+       FILE=`expr $1 : '\(.*\)\.Z' '|' $1`
+       gzip -cd $FILE | ${CMP-cmp} $OPTIONS - $FILE
+       STAT="$?"
+elif test $# -eq 2; then
+       case "$1" in
+       *.Z)    case "$2" in
+               *.Z)    F=`basename $2 .Z`
+                       gzip -cd $2 > /tmp/$F.$$
+                       gzip -cd $1 | ${CMP-cmp} $OPTIONS - /tmp/$F.$$
+                       STAT="$?";;
+               *)      gzip -cd $1 | ${CMP-cmp} $OPTIONS - $2;;
+               esac;;
+       *)      case "$2" in
+               *.Z)    F=`basename $2 .Z`
+                       gzip -cd $2 > /tmp/$F.$$
+                       ${CMP-cmp} $OPTIONS $1 /tmp/$F.$$
+                       STAT="$?";;
+               *)      ${CMP-cmp} $OPTIONS $1 $2
+                       STAT="$?";;
+               esac;;
+       esac
+       exit "$STAT"
+else
+       echo "Usage: zcmp [cmp_options] file [file]"
+       exit 1
+fi
diff --git a/usr/src/contrib/gzip/zcmp.1 b/usr/src/contrib/gzip/zcmp.1
new file mode 100644 (file)
index 0000000..8068850
--- /dev/null
@@ -0,0 +1,45 @@
+.TH ZCMP 1
+.SH NAME
+zcmp, zdiff \- compare compressed files
+.SH SYNOPSIS
+.B zcmp
+[ cmp_options ] file1
+[ file2 ]
+.br
+.B zdiff
+[ diff_options ] file1
+[ file2 ]
+.SH DESCRIPTION
+.I  Zcmp
+and 
+.I zdiff
+are used to invoke the
+.I cmp
+or the
+.I diff
+program on compressed files.  All options specified are passed directly to
+.I cmp
+or
+.IR diff "."
+If only 1 file is specified, then the files compared are
+.I file1
+and an uncompressed
+.IR file1 ".Z."
+If two files are specified, then they are uncompressed (if ending with ".Z")
+and fed to
+.I cmp
+or
+.IR diff "."
+The exit status from 
+.I cmp
+or
+.I diff
+is preserved.
+.SH "SEE ALSO"
+cmp(1), diff(1), zmore(1), znew(1), zforce(1), gzip(1), gzexe(1)
+.SH BUGS
+Messages from the
+.I cmp
+or
+.I diff
+programs refer to temporary filenames instead of those specified.
diff --git a/usr/src/contrib/gzip/zdiff b/usr/src/contrib/gzip/zdiff
new file mode 100644 (file)
index 0000000..01ad7ab
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Zcmp and zdiff are used to invoke the cmp or the  diff  pro-
+# gram  on compressed files.  All options specified are passed
+# directly to cmp or diff.  If only 1 file is specified,  then
+# the  files  compared  are file1 and an uncompressed file1.z.
+# If two files are specified, then they are  uncompressed  (if
+# ending  with  ".z") and fed to cmp or diff.  The exit status
+# from cmp or diff is preserved.
+
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+  *cmp) comp=${CMP-cmp}   ;;
+  *)    comp=${DIFF-diff} ;;
+esac
+
+OPTIONS=
+FILES=
+for ARG
+do
+    case "$ARG" in
+    -*)        OPTIONS="$OPTIONS $ARG";;
+     *)        if test -f "$ARG"; then
+            FILES="$FILES $ARG"
+        else
+            echo "${prog}: $ARG not found or not a regular file"
+           exit 1
+        fi ;;
+    esac
+done
+if test -z "$FILES"; then
+       echo "Usage: $prog [${comp}_options] file [file]"
+       exit 1
+fi
+set $FILES
+if test $# -eq 1; then
+       FILE=`echo "$1" | sed 's/[-.][zZtga]*$//'`
+       gzip -cd "$1" | $comp $OPTIONS - "$FILE"
+       STAT="$?"
+
+elif test $# -eq 2; then
+       case "$1" in
+        *[-.][zZ] | *.t[ga]z)
+                case "$2" in
+               *[-.][zZ] | *.t[ga]z)
+                       F=`echo "$2" | sed 's|.*/||;s|[-.][zZtga]*$||'`
+                        gzip -cd "$2" > /tmp/"$F".$$
+                        gzip -cd "$1" | $comp $OPTIONS - /tmp/"$F".$$
+                        STAT="$?"
+                       /bin/rm -f /tmp/"$F".$$;;
+
+                *)      gzip -cd "$1" | $comp $OPTIONS - "$2"
+                        STAT="$?";;
+                esac;;
+        *)      case "$2" in
+               *[-.][zZ] | *.t[ga]z)
+                        gzip -cd "$2" | $comp $OPTIONS "$1" -
+                        STAT="$?";;
+                *)      $comp $OPTIONS "$1" "$2"
+                        STAT="$?";;
+                esac;;
+       esac
+        exit "$STAT"
+else
+       echo "Usage: $prog [${comp}_options] file [file]"
+       exit 1
+fi
diff --git a/usr/src/contrib/gzip/zforce b/usr/src/contrib/gzip/zforce
new file mode 100644 (file)
index 0000000..5c1a588
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# zforce: force a z extension on all gzip files so that gzip will not
+# compress them twice.
+#
+# This can be useful for files with names truncated after a file transfer.
+# 12345678901234 is renamed to 123456789012.z
+
+x=`basename $0`
+if test $# = 0; then
+  echo "force a '.z' extension on all gzip files"
+  echo usage: $x files...
+  exit 1
+fi
+
+res=0
+for i do
+  if test ! -f "$i" ; then
+    echo ${x}: $i not a file
+    res=1
+    continue
+  fi
+  test `expr "$i" : '.*[.-]z$'` -eq 0 || continue
+  test `expr "$i" : '.*[.]t[ag]z$'` -eq 0 || continue
+
+  gzip -t "$i" 2>/dev/null || continue
+
+  if test `expr "$i" : '^.............$'` -eq 13; then
+    new=`expr "$i" : '\(.*\).$`.z
+  else
+    new="$i.z"
+  fi
+  if mv "$i" "$new" 2>/dev/null; then
+    echo $i -- replaced with $new
+    continue
+  fi
+  new=`expr "$i" : '\(.*\)..$`.z
+
+  if mv "$i" "$new" 2>/dev/null; then
+    echo $i -- replaced with $new
+    continue
+  fi
+  res=1; echo ${x}: cannot rename $i to $new
+done
+exit $res
diff --git a/usr/src/contrib/gzip/zforce.1 b/usr/src/contrib/gzip/zforce.1
new file mode 100644 (file)
index 0000000..c82ace1
--- /dev/null
@@ -0,0 +1,23 @@
+.TH ZFORCE 1
+.SH NAME
+zforce \- force a 'z' extension on all gzip files
+.SH SYNOPSIS
+.B zforce
+[ name ...  ]
+.SH DESCRIPTION
+.I  zforce
+forces a z extension on all
+.I gzip
+files so that
+.I gzip
+will not compress them twice.
+This can be useful for files with names truncated after a file transfer.
+On systems with a 14 char limitation on file names, the original name
+is truncated to make room for the .z suffix. For example,
+12345678901234 is renamed to 123456789012.z. A file name such as foo.tgz
+is left intact.
+.SH "SEE ALSO"
+gzip(1), znew(1), zmore(1), zcmp(1), gzexe(1)
+.SH BUGS
+File names of exactly 13 characters are first truncated to 12 characters
+even on file systems not limited to 14 characters.
diff --git a/usr/src/contrib/gzip/zip.c b/usr/src/contrib/gzip/zip.c
new file mode 100644 (file)
index 0000000..a257e9d
--- /dev/null
@@ -0,0 +1,113 @@
+/* zip.c -- compress files to the gzip or pkzip format
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: zip.c,v 0.15 1993/03/18 18:14:56 jloup Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif
+
+local ulg crc;       /* crc on uncompressed file data */
+long overhead;       /* number of bytes in gzip header */
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ *   The variables time_stamp and save_orig_name are initialized.
+ */
+void zip(in, out)
+    int in, out;            /* input and output file descriptors */
+{
+    uch  flags = 0;         /* general purpose bit flags */
+    ush  attr = 0;          /* ascii/binary flag */
+    ush  deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
+
+    ifd = in;
+    ofd = out;
+    outcnt = 0;
+
+    /* Write the header to the gzip file. See algorithm.doc for the format */
+
+    method = DEFLATED;
+    put_byte(GZIP_MAGIC[0]); /* magic header */
+    put_byte(GZIP_MAGIC[1]);
+    put_byte(DEFLATED);      /* compression method */
+
+    if (save_orig_name) {
+       flags |= ORIG_NAME;
+    }
+    put_byte(flags);         /* general flags */
+    put_long(time_stamp);
+
+    /* Write deflated file to zip file */
+    crc = updcrc(0, 0);
+
+    bi_init(out);
+    ct_init(&attr, &method);
+    lm_init(level, &deflate_flags);
+
+    put_byte((uch)deflate_flags); /* extra flags */
+    put_byte(OS_CODE);            /* OS identifier */
+
+    if (save_orig_name) {
+       char *p = basename(ifname); /* Don't save the directory part. */
+       do {
+           put_byte(*p);
+       } while (*p++);
+    }
+    overhead = (long)outcnt;
+
+    (void)deflate();
+
+#if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
+  /* Check input size (but not in VMS -- variable record lengths mess it up)
+   * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+   */
+    if (ifile_size != -1L && isize != (ulg)ifile_size) {
+       Trace((stderr, " actual=%ld, read=%ld ", ifile_size, isize));
+       fprintf(stderr, "%s: %s: file size changed while zipping\n",
+               progname, ifname);
+    }
+#endif
+
+    /* Write the crc and uncompressed size */
+    put_long(crc);
+    put_long(isize);
+
+    flush_outbuf();
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+int file_read(buf, size)
+    char *buf;
+    unsigned size;
+{
+    unsigned len;
+
+    Assert(insize == 0, "inbuf not empty");
+
+    len = read(ifd, buf, size);
+    if (len == (unsigned)(-1) || len == 0) return (int)len;
+
+    crc = updcrc((uch*)buf, len);
+    isize += (ulg)len;
+    return (int)len;
+}
diff --git a/usr/src/contrib/gzip/zmore b/usr/src/contrib/gzip/zmore
new file mode 100644 (file)
index 0000000..9aeb8c8
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if test "`echo -n a`" = "-n a"; then
+  # looks like a SysV system:
+  n1=''; n2='\c'
+else
+  n1='-n'; n2=''
+fi
+if stty -cbreak 2>/dev/null; then
+  cb='cbreak'; ncb='-cbreak'
+else
+  # 'stty min 1' resets eof to ^a on both SunOS and SysV!
+  cb='min 1 -icanon'; ncb='icanon eof ^d'
+fi
+trap 'stty $ncb echo 2>/dev/null; exit' 0 2 3 5 10 13 15
+if test $# = 0; then
+       gzip -cd | eval ${PAGER-more}
+else
+    FIRST=1
+    for FILE
+    do
+       if test $FIRST -eq 0; then
+               echo $n1 "--More--(Next file: $FILE)$n2"
+               stty $cb -echo 2>/dev/null
+               ANS=`dd bs=1 count=1 2>/dev/null` 
+               stty $ncb echo 2>/dev/null
+               echo " "
+               if test "$ANS" = 'e' -o "$ANS" = 'q'; then
+                       exit
+               fi
+       fi
+       if test "$ANS" != 's'; then
+               echo "------> $FILE <------"
+               gzip -cd "$FILE" | eval ${PAGER-more}
+       fi
+       if test -t; then
+               FIRST=0
+       fi
+    done
+fi
diff --git a/usr/src/contrib/gzip/zmore.1 b/usr/src/contrib/gzip/zmore.1
new file mode 100644 (file)
index 0000000..08b49fb
--- /dev/null
@@ -0,0 +1,134 @@
+.TH ZMORE 1
+.SH NAME
+zmore \- file perusal filter for crt viewing of compressed text
+.SH SYNOPSIS
+.B zmore
+[ name ...  ]
+.SH DESCRIPTION
+.I  Zmore
+is a filter which allows examination of compressed text files
+one screenful at a time on a soft-copy terminal.
+It normally pauses after each screenful, printing --More--
+at the bottom of the screen.
+If the user then types a carriage return, one more line is displayed.
+If the user hits a space,
+another screenful is displayed.  Other possibilities are enumerated later.
+.PP
+.I Zmore
+looks in the file
+.I /etc/termcap
+to determine terminal characteristics,
+and to determine the default window size.
+On a terminal capable of displaying 24 lines,
+the default window size is 22 lines.
+To use a pager other than the default
+.I more,
+set environment variable PAGER to the name of the desired program, such as
+.I less.
+.PP
+Other sequences which may be typed when
+.I zmore
+pauses, and their effects, are as follows (\fIi\fP is an optional integer
+argument, defaulting to 1) :
+.PP
+.IP \fIi\|\fP<space>
+display
+.I i
+more lines, (or another screenful if no argument is given)
+.PP
+.IP ^D
+display 11 more lines (a ``scroll'').
+If
+.I i
+is given, then the scroll size is set to \fIi\|\fP.
+.PP
+.IP d
+same as ^D (control-D)
+.PP
+.IP \fIi\|\fPz
+same as typing a space except that \fIi\|\fP, if present, becomes the new
+window size.  Note that the window size reverts back to the default at the
+end of the current file.
+.PP
+.IP \fIi\|\fPs
+skip \fIi\|\fP lines and print a screenful of lines
+.PP
+.IP \fIi\|\fPf
+skip \fIi\fP screenfuls and print a screenful of lines
+.PP
+.IP "q or Q"
+quit reading the current file; go on to the next (if any)
+.PP
+.IP "e or q"
+When the prompt --More--(Next file: 
+.IR file )
+is printed, this command causes zmore to exit.
+.PP
+.IP s
+When the prompt --More--(Next file: 
+.IR file )
+is printed, this command causes zmore to skip the next file and continue.
+.PP 
+.IP =
+Display the current line number.
+.PP
+.IP \fIi\|\fP/expr
+search for the \fIi\|\fP-th occurrence of the regular expression \fIexpr.\fP
+If the pattern is not found,
+.I zmore
+goes on to the next file (if any).
+Otherwise, a screenful is displayed, starting two lines before the place
+where the expression was found.
+The user's erase and kill characters may be used to edit the regular
+expression.
+Erasing back past the first column cancels the search command.
+.PP
+.IP \fIi\|\fPn
+search for the \fIi\|\fP-th occurrence of the last regular expression entered.
+.PP
+.IP !command
+invoke a shell with \fIcommand\|\fP. 
+The character `!' in "command" are replaced with the
+previous shell command.  The sequence "\\!" is replaced by "!".
+.PP
+.IP ":q or :Q"
+quit reading the current file; go on to the next (if any)
+(same as q or Q).
+.PP
+.IP .
+(dot) repeat the previous command.
+.PP
+The commands take effect immediately, i.e., it is not necessary to
+type a carriage return.
+Up to the time when the command character itself is given,
+the user may hit the line kill character to cancel the numerical
+argument being formed.
+In addition, the user may hit the erase character to redisplay the
+--More-- message.
+.PP
+At any time when output is being sent to the terminal, the user can
+hit the quit key (normally control\-\\).
+.I Zmore
+will stop sending output, and will display the usual --More--
+prompt.
+The user may then enter one of the above commands in the normal manner.
+Unfortunately, some output is lost when this is done, due to the
+fact that any characters waiting in the terminal's output queue
+are flushed when the quit signal occurs.
+.PP
+The terminal is set to
+.I noecho
+mode by this program so that the output can be continuous.
+What you type will thus not show on your terminal, except for the / and !
+commands.
+.PP
+If the standard output is not a teletype, then
+.I zmore
+acts just like
+.I zcat,
+except that a header is printed before each file.
+.SH FILES
+.DT
+/etc/termcap           Terminal data base
+.SH "SEE ALSO"
+more(1), gzip(1), zcmp(1), znew(1), zforce(1), gzexe(1)
diff --git a/usr/src/contrib/gzip/znew b/usr/src/contrib/gzip/znew
new file mode 100644 (file)
index 0000000..9bfec94
--- /dev/null
@@ -0,0 +1,125 @@
+#!/bin/sh
+
+check=0
+pipe=0
+opt=
+files=
+keep=0
+res=0
+old=0
+new=0
+block=1024
+# block is the disk block size (best guess, need not be exact)
+
+warn="(does not preserve modes and timestamp)"
+echo hi > zfoo1$$
+echo hi > zfoo2$$
+if test -z "`(${CPMOD-cpmod} zfoo1$$ zfoo2$$) 2>&1`"; then
+  cpmod=${CPMOD-cpmod}
+  warn=""
+fi
+
+if test -z "$cpmod" && ${TOUCH-touch} -r zfoo1$$ zfoo2$$ 2>/dev/null; then
+  cpmod="${TOUCH-touch}"
+  cpmodarg="-r"
+  warn="(does not preserve file modes)"
+fi
+rm -f zfoo[12]$$
+
+for arg
+do
+  case "$arg" in
+  -*)     opt="$opt $arg";;
+   *)     files="$files $arg";;
+  esac
+done
+
+if test -z "$files"; then
+  echo 'recompress .Z files into .z (gzip) files'
+  echo usage: `echo $0 | sed 's,^.*/,,'` "[-tv9P]" file.Z...
+  echo "  -t tests the new files before deleting originals"
+  echo "  -v be verbose"
+  echo "  -9 use the slowest compression method (optimal compression)"
+  echo "  -K keep a .Z file when it is smaller than the .z file"
+  echo "  -P use pipes for the conversion $warn"
+  exit 1
+fi
+opt=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'`
+case "$opt" in
+  *t*) check=1; opt=`echo "$opt" | sed 's/t//g'`
+esac
+case "$opt" in
+  *K*) keep=1; opt=`echo "$opt" | sed 's/K//g'`
+esac
+case "$opt" in
+  *P*) pipe=1; opt=`echo "$opt" | sed 's/P//g'`
+esac
+if test -n "$opt"; then
+  opt="-$opt"
+fi
+
+for i in $files; do
+  n=`echo $i | sed 's/.Z$//'`
+  if test ! -f $n.Z ; then
+    echo $n.Z not found
+    res=1; continue
+  fi
+  test $keep -eq 1 && old=`wc -c < $n.Z`
+  if test $pipe -eq 1; then
+    if gzip -d < $n.Z | gzip $opt > $n.z; then
+      # Copy file attributes from old file to new one, if possible.
+      test -n "$cpmod" && $cpmod $cpmodarg $n.Z $n.z 2> /dev/null
+    else
+      echo error while recompressing $n.Z
+      res=1; continue
+    fi
+  else
+    if test $check -eq 1; then
+      if cp -p $n.Z $n.$$ 2> /dev/null || cp $n.Z $n.$$; then
+       :
+      else
+       echo cannot backup $n.Z
+        res=1; continue
+      fi
+    fi
+    if gzip -d $n.Z; then
+      :
+    else
+      test $check -eq 1 && mv $n.$$ $n.Z
+      echo error while uncompressing $n.Z
+      res=1; continue
+    fi
+    if gzip $opt $n; then
+      :
+    else
+      test $check -eq 1 && mv $n.$$ $n.Z
+      echo error while recompressing $n
+      res=1; continue
+    fi
+  fi
+  test $keep -eq 1 && new=`wc -c < $n.z`
+  if test $keep -eq 1 -a `expr \( $old + $block - 1 \) / $block` -lt \
+                         `expr \( $new + $block - 1 \) / $block`; then
+    if test $pipe -eq 1; then
+      rm -f $n.z
+    elif test $check -eq 1; then
+      mv $n.$$ $n.Z && rm -f $n.z
+    else
+      gzip -d $n.z && compress $n && rm -f $n.z
+    fi
+    echo "$n.Z smaller than $n.z -- unchanged"
+
+  elif test $check -eq 1; then
+    if gzip -t $n.z ; then
+      rm -f $n.$$ $n.Z
+    else
+      test $pipe -eq 0 && mv $n.$$ $n.Z
+      rm -f $n.z
+      echo error while testing $n.z, $n.Z unchanged
+      res=1; continue
+    fi
+  elif test $pipe -eq 1; then
+    rm -f $n.Z
+  fi
+done
+exit $res
diff --git a/usr/src/contrib/gzip/znew.1 b/usr/src/contrib/gzip/znew.1
new file mode 100644 (file)
index 0000000..8e1a832
--- /dev/null
@@ -0,0 +1,31 @@
+.TH ZNEW 1
+.SH NAME
+znew \-   recompress .Z files to .z files
+.SH SYNOPSIS
+.B znew
+[ -tv9PK] [ name.Z ...  ]
+.SH DESCRIPTION
+.I  Znew
+recompresses files from .Z (compress) format to .z (gzip) format.
+.SH OPTIONS
+.TP
+.B \-t
+Tests the new files before deleting originals.
+.TP
+.B \-v
+Verbose. Display the name and percentage reduction for each file compressed.
+.TP
+.B \-9
+Use the slowest compression method (optimal compression).
+.TP
+.B \-P
+Use pipes for the conversion to reduce disk space usage.
+.TP
+.B \-K
+Keep a .Z file when it is smaller than the .z file
+.SH "SEE ALSO"
+gzip(1), zmore(1), zcmp(1), zforce(1), gzexe(1), compress(1)
+.SH BUGS
+.I Znew
+does not maintain the time stamp with the -P option if 'touch' does
+not support the -r option.
diff --git a/usr/src/contrib/tcpdump/Makefile b/usr/src/contrib/tcpdump/Makefile
new file mode 100644 (file)
index 0000000..0a1f253
--- /dev/null
@@ -0,0 +1,5 @@
+#      @(#)Makefile    0.1 (RGrimes) 4/4/93
+
+SUBDIR=        tcpdump tcpslice
+
+.include <bsd.subdir.mk>
diff --git a/usr/src/contrib/tcpdump/Makefile.inc b/usr/src/contrib/tcpdump/Makefile.inc
new file mode 100644 (file)
index 0000000..9489995
--- /dev/null
@@ -0,0 +1,3 @@
+#      @(#)Makefile.inc        5.1 (Berkeley) 5/11/90
+
+BINDIR?=       /usr/local/bin
diff --git a/usr/src/contrib/tcpdump/tcpdump/Makefile b/usr/src/contrib/tcpdump/tcpdump/Makefile
new file mode 100644 (file)
index 0000000..fee9554
--- /dev/null
@@ -0,0 +1,24 @@
+#      @(#)Makefile    0.1 (RWGrimes) 3/24/93
+
+PROG=  tcpdump
+CFLAGS+=-DCSLIP -I.
+MAN1=  tcpdump.0
+SRCS=  version.c addrtoname.c bpf_dump.c bpf_filter.c bpf_image.c etherent.c \
+       gencode.c inet.c md.c nametoaddr.c optimize.c os.c pcap.c \
+       print-arp.c print-atalk.c print-bootp.c print-domain.c \
+       print-egp.c print-ether.c print-fddi.c print-icmp.c print-ip.c \
+       print-nfs.c print-ntp.c print-null.c print-ospf.c print-ppp.c \
+       print-rip.c print-sl.c print-snmp.c print-sunrpc.c print-tcp.c \
+       print-tftp.c print-udp.c savefile.c tcpdump.c tcpgram.c \
+       tcplex.c util.c
+.PATH: /sys/net
+CLEANFILES+=   tcpgram.c tcplex.c y.tab.h y.tab.c version.c version.h
+
+version.c version.h: VERSION
+       rm -f version.c ; \
+       sed 's/.*/char version[] = "&";/' $(.CURDIR)/VERSION > version.c
+       set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/VERSION` ; \
+               { echo '#define VERSION_MAJOR' $$1 ; \
+                 echo '#define VERSION_MINOR' $$2 ; } > version.h
+
+.include <bsd.prog.mk>
diff --git a/usr/src/contrib/tcpdump/tcpdump/VERSION b/usr/src/contrib/tcpdump/tcpdump/VERSION
new file mode 100644 (file)
index 0000000..c043eea
--- /dev/null
@@ -0,0 +1 @@
+2.2.1
diff --git a/usr/src/contrib/tcpdump/tcpdump/addrtoname.c b/usr/src/contrib/tcpdump/tcpdump/addrtoname.c
new file mode 100644 (file)
index 0000000..5c70865
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 1988, 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Internet, ethernet, port, and protocol string to address
+ *  and address to string conversion routines
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: addrtoname.c,v 1.14 92/05/25 14:29:07 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <signal.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "nametoaddr.h"
+#include "etherent.h"
+
+/*
+ * hash tables for whatever-to-name translations
+ */
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+       u_long addr;
+       char *name;
+       struct hnamemem *nxt;
+};
+
+struct hnamemem hnametable[HASHNAMESIZE];
+struct hnamemem tporttable[HASHNAMESIZE];
+struct hnamemem uporttable[HASHNAMESIZE];
+struct hnamemem eprototable[HASHNAMESIZE];
+
+struct enamemem {
+       u_short e_addr0;
+       u_short e_addr1;
+       u_short e_addr2;
+       char *e_name;
+       struct enamemem *e_nxt;
+};
+
+struct enamemem enametable[HASHNAMESIZE];
+
+
+/*
+ * A faster replacement for inet_ntoa().
+ */
+char *
+intoa(addr)
+       u_long addr;
+{
+       register char *cp;
+       register u_int byte;
+       register int n;
+       static char buf[sizeof(".xxx.xxx.xxx.xxx")];
+
+       NTOHL(addr);
+       cp = &buf[sizeof buf];
+       *--cp = '\0';
+
+       n = 4;
+       do {
+               byte = addr & 0xff;
+               *--cp = byte % 10 + '0';
+               byte /= 10;
+               if (byte > 0) {
+                       *--cp = byte % 10 + '0';
+                       byte /= 10;
+                       if (byte > 0)
+                               *--cp = byte + '0';
+               }
+               *--cp = '.';
+               addr >>= 8;
+       } while (--n > 0);
+
+       return cp + 1;
+}
+
+static u_long f_netmask;
+static u_long f_localnet;
+static u_long netmask;
+
+/*
+ * "getname" is written in this atrocious way to make sure we don't
+ * wait forever while trying to get hostnames from yp.
+ */
+#include <setjmp.h>
+
+jmp_buf getname_env;
+
+static void
+nohostname()
+{
+       longjmp(getname_env, 1);
+}
+
+/*
+ * Return a name for the IP address pointed to by ap.  This address
+ * is assumed to be in network byte order.
+ */
+char *
+getname(ap)
+       u_char *ap;
+{
+       register struct hnamemem *p;
+       register struct hostent *hp;
+       register char *cp;
+       u_long addr;
+
+#ifndef TCPDUMP_ALIGN
+       addr = *(u_long *)ap;
+#else
+       /*
+        * Deal with alignment.
+        */
+       switch ((int)ap & 3) {
+
+       case 0:
+               addr = *(u_long *)ap;
+               break;
+
+       case 2:
+#if BYTE_ORDER == LITTLE_ENDIAN
+               addr = ((u_long)*(u_short *)(ap + 2) << 16) | 
+                       (u_long)*(u_short *)ap;
+#else
+               addr = ((u_long)*(u_short *)ap << 16) | 
+                       (u_long)*(u_short *)(ap + 2);
+#endif
+               break;
+
+       default:
+#if BYTE_ORDER == LITTLE_ENDIAN
+               addr = ((u_long)ap[0] << 24) |
+                       ((u_long)ap[1] << 16) |
+                       ((u_long)ap[2] << 8) |
+                       (u_long)ap[3];
+#else
+               addr = ((u_long)ap[3] << 24) |
+                       ((u_long)ap[2] << 16) |
+                       ((u_long)ap[1] << 8) |
+                       (u_long)ap[0];
+#endif
+               break;
+       }
+#endif
+       p = &hnametable[addr & (HASHNAMESIZE-1)]; 
+       for (; p->nxt; p = p->nxt) {
+               if (p->addr == addr)
+                       return (p->name);
+       }
+       p->addr = addr;
+       p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
+
+       /*
+        * Only print names when:
+        *      (1) -n was not given.
+        *      (2) Address is foreign and -f was given.  If -f was not 
+        *          present, f_netmask and f_local are 0 and the second
+        *          test will succeed.
+        *      (3) The host portion is not 0 (i.e., a network address).
+        *      (4) The host portion is not broadcast.
+        */
+       if (!nflag && (addr & f_netmask) == f_localnet
+           && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) {
+               if (!setjmp(getname_env)) {
+                       (void)signal(SIGALRM, nohostname);
+                       (void)alarm(20);
+                       hp = gethostbyaddr((char *)&addr, 4, AF_INET);
+                       (void)alarm(0);
+                       if (hp) {
+                               char *index();
+                               char *dotp;     
+                               u_int len = strlen(hp->h_name) + 1;
+                               p->name = (char *)malloc(len);
+                               (void)strcpy(p->name, hp->h_name);
+                               if (Nflag) {
+                                       /* Remove domain qualifications */
+                                       dotp = index(p->name, '.');
+                                       if (dotp)
+                                               *dotp = 0;
+                               }
+                               return (p->name);
+                       }
+               }
+       }
+       cp = intoa(addr);
+       p->name = (char *)malloc((unsigned)(strlen(cp) + 1));
+       (void)strcpy(p->name, cp);
+       return (p->name);
+}
+
+static char hex[] = "0123456789abcdef";
+
+
+/* Find the hash node that corresponds the ether address 'ep'. */
+
+static inline struct enamemem *
+lookup_emem(ep)
+       u_char *ep;
+{
+       register u_int i, j, k;
+       struct enamemem *tp;
+
+       k = (ep[0] << 8) | ep[1];
+       j = (ep[2] << 8) | ep[3];
+       i = (ep[4] << 8) | ep[5];
+
+       tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
+       while (tp->e_nxt)
+               if (tp->e_addr0 == i &&
+                   tp->e_addr1 == j &&
+                   tp->e_addr2 == k)
+                       return tp;
+               else
+                       tp = tp->e_nxt;
+       tp->e_addr0 = i;
+       tp->e_addr1 = j;
+       tp->e_addr2 = k;
+       tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
+
+       return tp;
+}
+
+char *
+etheraddr_string(ep)
+       register u_char *ep;
+{
+       register u_int i, j;
+       register char *cp;
+       register struct enamemem *tp;
+
+       tp = lookup_emem(ep);
+       if (tp->e_name)
+               return tp->e_name;
+
+#ifdef ETHER_SERVICE
+       if (!nflag) {
+               cp = ETHER_ntohost(ep);
+               if (cp) {
+                       tp->e_name = cp;
+                       return cp;
+               }
+       }
+#endif         
+       tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
+
+       if (j = *ep >> 4)
+               *cp++ = hex[j];
+       *cp++ = hex[*ep++ & 0xf];
+       for (i = 5; (int)--i >= 0;) {
+               *cp++ = ':';
+               if (j = *ep >> 4)
+                       *cp++ = hex[j];
+               *cp++ = hex[*ep++ & 0xf];
+       }
+       *cp = '\0';
+       return (tp->e_name);
+}
+
+char *
+etherproto_string(port)
+       u_short port;
+{
+       register char *cp;
+       register struct hnamemem *tp;
+       register u_long i = port;
+
+       for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+               if (tp->addr == i)
+                       return (tp->name);
+
+       tp->name = cp = (char *)malloc(sizeof("0000"));
+       tp->addr = i;
+       tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
+
+       NTOHS(port);
+       *cp++ = hex[port >> 12 & 0xf];
+       *cp++ = hex[port >> 8 & 0xf];
+       *cp++ = hex[port >> 4 & 0xf];
+       *cp++ = hex[port & 0xf];
+       *cp++ = '\0';
+       return (tp->name);
+}
+
+char *
+tcpport_string(port)
+       u_short port;
+{
+       register struct hnamemem *tp;
+       register int i = port;
+
+       for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+               if (tp->addr == i)
+                       return (tp->name);
+
+       tp->name = (char *)malloc(sizeof("00000"));
+       tp->addr = i;
+       tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
+
+       (void)sprintf(tp->name, "%d", i);
+       return (tp->name);
+}
+
+char *
+udpport_string(port)
+       register u_short port;
+{
+       register struct hnamemem *tp;
+       register int i = port;
+
+       for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+               if (tp->addr == i)
+                       return (tp->name);
+
+       tp->name = (char *)malloc(sizeof("00000"));
+       tp->addr = i;
+       tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+
+       (void)sprintf(tp->name, "%d", i);
+
+       return (tp->name);
+}
+
+static void
+init_servarray()
+{
+       struct servent *sv;
+       register struct hnamemem *table;
+       register int i;
+
+       while (sv = getservent()) {
+               NTOHS(sv->s_port);
+               i = sv->s_port & (HASHNAMESIZE-1);
+               if (strcmp(sv->s_proto, "tcp") == 0)
+                       table = &tporttable[i];
+               else if (strcmp(sv->s_proto, "udp") == 0)
+                       table = &uporttable[i];
+               else
+                       continue;
+
+               while (table->name)
+                       table = table->nxt;
+               if (nflag) {
+                       char buf[32];
+
+                       (void)sprintf(buf, "%d", sv->s_port);
+                       table->name = (char *)malloc((unsigned)strlen(buf)+1);
+                       (void)strcpy(table->name, buf);
+               } else {
+                       table->name =
+                               (char *)malloc((unsigned)strlen(sv->s_name)+1);
+                       (void)strcpy(table->name, sv->s_name);
+               }
+               table->addr = sv->s_port;
+               table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+       }
+       endservent();
+}
+
+#include "etherproto.h"
+
+/* Static data base of ether protocol types. */
+struct eproto eproto_db[] = { 
+       { "pup", ETHERTYPE_PUP },
+       { "xns", ETHERTYPE_NS },
+       { "ip", ETHERTYPE_IP },
+       { "arp", ETHERTYPE_ARP },
+       { "rarp", ETHERTYPE_REVARP },
+       { "sprite", ETHERTYPE_SPRITE },
+       { "mopdl", ETHERTYPE_MOPDL },
+       { "moprc", ETHERTYPE_MOPRC },
+       { "decnet", ETHERTYPE_DN },
+       { "lat", ETHERTYPE_LAT },
+       { "lanbridge", ETHERTYPE_LANBRIDGE },
+       { "vexp", ETHERTYPE_VEXP },
+       { "vprod", ETHERTYPE_VPROD },
+       { "atalk", ETHERTYPE_ATALK },
+       { "atalkarp", ETHERTYPE_AARP },
+       { "loopback", ETHERTYPE_LOOPBACK },
+       { (char *)0, 0 }
+};
+
+static void
+init_eprotoarray()
+{
+       register int i;
+       register struct hnamemem *table;
+
+       for (i = 0; eproto_db[i].s; i++) {
+               int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
+               table = &eprototable[j];
+               while (table->name)
+                       table = table->nxt;
+               table->name = eproto_db[i].s;
+               table->addr = ntohs(eproto_db[i].p);
+               table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+       }
+}
+
+static void
+init_etherarray()
+{
+#ifndef ETHER_SERVICE
+       FILE *fp;
+       struct etherent *ep;
+       struct enamemem *tp;
+
+       fp = fopen(ETHERS_FILE, "r");
+       if (fp == 0)
+               /* No data base; will have to settle for 
+                  numeric addresses. */
+               return;
+
+       while (ep = next_etherent(fp)) {
+               tp = lookup_emem(ep->addr);
+               tp->e_name = (char *)malloc((unsigned)strlen(ep->name)+1);
+               strcpy(tp->e_name, ep->name);
+       }
+#endif
+}
+
+/*
+ * Initialize the address to name translation machinery.  We map all
+ * non-local IP addresses to numeric addresses if fflag is true (i.e.,
+ * to prevent blocking on the nameserver).  localnet is the IP address
+ * of the local network.  mask is its subnet mask.
+ */
+void
+init_addrtoname(fflag, localnet, mask)
+       int fflag;
+       u_long localnet;
+       u_long mask;
+{
+       netmask = mask;
+       if (fflag) {
+               f_localnet = localnet;
+               f_netmask = mask;
+       }
+       if (nflag)
+               /*
+                * Simplest way to suppress names.
+                */
+               return;
+
+       init_etherarray();
+       init_servarray();
+       init_eprotoarray();
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/addrtoname.h b/usr/src/contrib/tcpdump/tcpdump/addrtoname.h
new file mode 100644 (file)
index 0000000..6dc6979
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1988, 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: addrtoname.h,v 1.5 92/03/17 13:41:37 mccanne Exp $ (LBL)
+ */
+
+/* Name to address translation routines. */
+
+extern char *etheraddr_string();
+extern char *etherproto_string();
+extern char *tcpport_string();
+extern char *udpport_string();
+extern char *getname();
+extern char *intoa();
+
+extern void init_addrtoname();
+extern void no_foreign_names();
+
+#define ipaddr_string(p) getname((u_char *)(p))
diff --git a/usr/src/contrib/tcpdump/tcpdump/appletalk.h b/usr/src/contrib/tcpdump/tcpdump/appletalk.h
new file mode 100644 (file)
index 0000000..90c8c80
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1988 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * AppleTalk protocol formats (courtesy Bill Croft of Stanford/SUMEX).
+ *
+ * @(#) $Header: appletalk.h,v 1.6 90/10/03 22:14:26 leres Exp $ (LBL)
+ */
+
+/* Datagram Delivery Protocol */
+
+struct atDDP {
+       u_short length;
+       u_short checksum;
+       u_short dstNet;
+       u_short srcNet;
+       u_char  dstNode;
+       u_char  srcNode;
+       u_char  dstSkt;
+       u_char  srcSkt;
+       u_char  type;
+};
+
+struct atShortDDP {
+       u_short length;
+       u_char  dstSkt;
+       u_char  srcSkt;
+       u_char  type;
+};
+
+#define        ddpMaxWKS       0x7F
+#define        ddpMaxData      586
+#define        ddpLengthMask   0x3FF
+#define        ddpHopShift     10
+#define        ddpSize         13      /* size of DDP header (avoid struct padding) */
+#define        ddpSSize        5
+#define        ddpWKS          128     /* boundary of DDP well known sockets */
+#define        ddpRTMP         1       /* RTMP type */
+#define        ddpRTMPrequest  5       /* RTMP request type */
+#define        ddpNBP          2       /* NBP type */
+#define        ddpATP          3       /* ATP type */
+#define        ddpECHO         4       /* ECHO type */
+#define        ddpIP           22      /* IP type */
+#define        ddpARP          23      /* ARP type */
+#define        ddpKLAP         0x4b    /* Kinetics KLAP type */
+
+
+/* AppleTalk Transaction Protocol */
+
+struct atATP {
+       u_char  control;
+       u_char  bitmap;
+       u_short transID;
+       long    userData;
+};
+
+#define        atpReqCode      0x40
+#define        atpRspCode      0x80
+#define        atpRelCode      0xC0
+#define        atpXO           0x20
+#define        atpEOM          0x10
+#define        atpSTS          0x08
+#define        atpFlagMask     0x3F
+#define        atpControlMask  0xF8
+#define        atpMaxNum       8
+#define        atpMaxData      578
+
+
+/* AppleTalk Echo Protocol */
+
+struct atEcho {
+       u_char  echoFunction;
+       u_char  *echoData;
+};
+
+#define echoSkt                4               /* the echoer socket */
+#define echoSize       1               /* size of echo header */
+#define echoRequest    1               /* echo request */
+#define echoReply      2               /* echo request */
+
+
+/* Name Binding Protocol */
+
+struct atNBP {
+       u_char  control;
+       u_char  id;
+};
+
+struct atNBPtuple {
+       u_short net;
+       u_char  node;
+       u_char  skt;
+       u_char  enumerator;
+};
+
+#define        nbpBrRq         0x10
+#define        nbpLkUp         0x20
+#define        nbpLkUpReply    0x30
+
+#define        nbpNIS          2
+#define        nbpTupleMax     15
+
+#define        nbpHeaderSize   2
+#define nbpTupleSize   5;
+
+
+/* Routing Table Maint. Protocol */
+
+#define        rtmpSkt         1       /* number of RTMP socket */
+#define        rtmpSize        4       /* minimum size */
+#define        rtmpTupleSize   3
+
+
+/* Zone Information Protocol */
+
+struct zipHeader {
+       u_char  command;
+       u_char  netcount;
+};
+
+#define        zipHeaderSize   2
+#define        zipQuery        1
+#define        zipReply        2
+#define        zipTakedown     3
+#define        zipBringup      4
+#define        ddpZIP          6
+#define        zipSkt          6
+#define        GetMyZone       7
+#define        GetZoneList     8
+
+/*
+ * UDP port range used for ddp-in-udp encapsulation is 16512-16639
+ * for client sockets (128-255) and 200-327 for server sockets
+ * (0-127).  We also try to recognize the pre-April 88 server
+ * socket range of 768-895.
+ */
+#define atalk_port(p) \
+       (((unsigned)((p) - 16512) < 128) || \
+        ((unsigned)((p) - 200) < 128) || \
+        ((unsigned)((p) - 768) < 128))
diff --git a/usr/src/contrib/tcpdump/tcpdump/bootp.h b/usr/src/contrib/tcpdump/tcpdump/bootp.h
new file mode 100644 (file)
index 0000000..ab474cf
--- /dev/null
@@ -0,0 +1,103 @@
+/* @(#) $Header: bootp.h,v 1.2 90/05/29 21:29:16 leres Exp $ (LBL) */
+/*
+ * Bootstrap Protocol (BOOTP).  RFC951 and RFC1048.
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ * Copyright 1988 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University.  Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+
+struct bootp {
+       unsigned char   bp_op;          /* packet opcode type */
+       unsigned char   bp_htype;       /* hardware addr type */
+       unsigned char   bp_hlen;        /* hardware addr length */
+       unsigned char   bp_hops;        /* gateway hops */
+       unsigned long   bp_xid;         /* transaction ID */
+       unsigned short  bp_secs;        /* seconds since boot began */
+       unsigned short  bp_unused;
+       struct in_addr  bp_ciaddr;      /* client IP address */
+       struct in_addr  bp_yiaddr;      /* 'your' IP address */
+       struct in_addr  bp_siaddr;      /* server IP address */
+       struct in_addr  bp_giaddr;      /* gateway IP address */
+       unsigned char   bp_chaddr[16];  /* client hardware address */
+       unsigned char   bp_sname[64];   /* server host name */
+       unsigned char   bp_file[128];   /* boot file name */
+       unsigned char   bp_vend[64];    /* vendor-specific area */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define        IPPORT_BOOTPS           67
+#define        IPPORT_BOOTPC           68
+
+#define BOOTREPLY              2
+#define BOOTREQUEST            1
+
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU         "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048     { 99, 130, 83, 99 }
+
+\f
+
+/*
+ * RFC1048 tag values used to specify what information is being supplied in
+ * the vendor field of the packet.
+ */
+
+#define TAG_PAD                        ((unsigned char)   0)
+#define TAG_SUBNET_MASK                ((unsigned char)   1)
+#define TAG_TIME_OFFSET                ((unsigned char)   2)
+#define TAG_GATEWAY            ((unsigned char)   3)
+#define TAG_TIME_SERVER                ((unsigned char)   4)
+#define TAG_NAME_SERVER                ((unsigned char)   5)
+#define TAG_DOMAIN_SERVER      ((unsigned char)   6)
+#define TAG_LOG_SERVER         ((unsigned char)   7)
+#define TAG_COOKIE_SERVER      ((unsigned char)   8)
+#define TAG_LPR_SERVER         ((unsigned char)   9)
+#define TAG_IMPRESS_SERVER     ((unsigned char)  10)
+#define TAG_RLP_SERVER         ((unsigned char)  11)
+#define TAG_HOSTNAME           ((unsigned char)  12)
+#define TAG_BOOTSIZE           ((unsigned char)  13)
+#define TAG_END                        ((unsigned char) 255)
+
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+       unsigned char   v_magic[4];     /* magic number */
+       unsigned long   v_flags;        /* flags/opcodes, etc. */
+       struct in_addr  v_smask;        /* Subnet mask */
+       struct in_addr  v_dgate;        /* Default gateway */
+       struct in_addr  v_dns1, v_dns2; /* Domain name servers */
+       struct in_addr  v_ins1, v_ins2; /* IEN-116 name servers */
+       struct in_addr  v_ts1, v_ts2;   /* Time servers */
+       unsigned char   v_unused[25];   /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK       1       /* Subnet mask field contains valid data */
diff --git a/usr/src/contrib/tcpdump/tcpdump/bpf_dump.c b/usr/src/contrib/tcpdump/tcpdump/bpf_dump.c
new file mode 100644 (file)
index 0000000..fab9596
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: bpf_dump.c,v 1.1 92/01/29 13:25:30 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+void
+bpf_dump(p, option)
+       struct bpf_program *p;
+       int option;
+{
+       struct bpf_insn *insn;
+       int i;
+       int n = p->bf_len;
+
+       insn = p->bf_insns;
+       if (option > 2) {
+               printf("%d\n", n);
+               for (i = 0; i < n; ++insn, ++i) {
+                       printf("%lu %lu %lu %lu\n", insn->code,
+                              insn->jt, insn->jf, insn->k);
+               }
+               return ;
+       }
+       if (option > 1) {
+               for (i = 0; i < n; ++insn, ++i)
+                       printf("{ 0x%x, %d, %d, 0x%08x },\n", 
+                              insn->code, insn->jt, insn->jf, insn->k);
+               return;
+       }
+       for (i = 0; i < n; ++insn, ++i) {
+#ifdef BDEBUG
+               extern int bids[];
+               printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1);
+#endif
+               puts(bpf_image(insn, i));
+       }
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/bpf_image.c b/usr/src/contrib/tcpdump/tcpdump/bpf_image.c
new file mode 100644 (file)
index 0000000..d36eab2
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+       "@(#) $Header: bpf_image.c,v 1.10 92/01/26 21:01:16 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+char *
+bpf_image(p, n)
+       struct bpf_insn *p;
+       int n;
+{
+       int v;
+       char *fmt, *op;
+       static char image[256];
+       char operand[64];
+       
+       v = p->k;
+       switch (p->code) {
+               
+       default:
+               op = "unimp";
+               fmt = "0x%x";
+               v = p->code;
+               break;
+                       
+       case BPF_RET|BPF_K:
+               op = "ret";
+               fmt = "#%d";
+               break;
+
+       case BPF_RET|BPF_A:
+               op = "ret";
+               fmt = "";
+               break;
+
+       case BPF_LD|BPF_W|BPF_ABS:
+               op = "ld";
+               fmt = "[%d]";
+               break;
+
+       case BPF_LD|BPF_H|BPF_ABS:
+               op = "ldh";
+               fmt = "[%d]";
+               break;
+
+       case BPF_LD|BPF_B|BPF_ABS:
+               op = "ldb";
+               fmt = "[%d]";
+               break;
+
+       case BPF_LD|BPF_W|BPF_LEN:
+               op = "ld";
+               fmt = "#pktlen";
+               break;
+
+       case BPF_LD|BPF_W|BPF_IND:
+               op = "ld";
+               fmt = "[x + %d]";
+               break;
+
+       case BPF_LD|BPF_H|BPF_IND:
+               op = "ldh";
+               fmt = "[x + %d]";
+               break;
+
+       case BPF_LD|BPF_B|BPF_IND:
+               op = "ldb";
+               fmt = "[x + %d]";
+               break;
+
+       case BPF_LD|BPF_IMM:
+               op = "ld";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_LDX|BPF_IMM:
+               op = "ldx";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_LDX|BPF_MSH|BPF_B:
+               op = "ldxb";
+               fmt = "4*([%d]&0xf)";
+               break;
+                       
+       case BPF_LD|BPF_MEM:
+               op = "ld";
+               fmt = "M[%d]";
+               break;
+                       
+       case BPF_LDX|BPF_MEM:
+               op = "ldx";
+               fmt = "M[%d]";
+               break;
+
+       case BPF_ST:
+               op = "st";
+               fmt = "M[%d]";
+               break;
+
+       case BPF_STX:
+               op = "stx";
+               fmt = "M[%d]";
+               break;
+
+       case BPF_JMP|BPF_JA:
+               op = "ja";
+               fmt = "%d";
+               v = n + p->k;
+               break;
+
+       case BPF_JMP|BPF_JGT|BPF_K:
+               op = "jgt";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_JMP|BPF_JGE|BPF_K:
+               op = "jge";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_JMP|BPF_JEQ|BPF_K:
+               op = "jeq";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_JMP|BPF_JSET|BPF_K:
+               op = "jset";
+               fmt = "#0x%x";
+               break;
+
+       case BPF_JMP|BPF_JGT|BPF_X:
+               op = "jgt";
+               fmt = "x";
+               break;
+
+       case BPF_JMP|BPF_JGE|BPF_X:
+               op = "jge";
+               fmt = "x";
+               break;
+
+       case BPF_JMP|BPF_JEQ|BPF_X:
+               op = "jeq";
+               fmt = "x";
+               break;
+
+       case BPF_JMP|BPF_JSET|BPF_X:
+               op = "jset";
+               fmt = "x";
+               break;
+
+       case BPF_ALU|BPF_ADD|BPF_X:
+               op = "add";
+               fmt = "x";
+               break;
+
+       case BPF_ALU|BPF_SUB|BPF_X:
+               op = "sub";
+               fmt = "x";
+               break;
+                       
+       case BPF_ALU|BPF_MUL|BPF_X:
+               op = "mul";
+               fmt = "x";
+               break;
+                       
+       case BPF_ALU|BPF_DIV|BPF_X:
+               op = "div";
+               fmt = "x";
+               break;
+                       
+       case BPF_ALU|BPF_AND|BPF_X:
+               op = "and";
+               fmt = "x";
+               break;
+                       
+       case BPF_ALU|BPF_OR|BPF_X:
+               op = "or";
+               fmt = "x";
+               break;
+
+       case BPF_ALU|BPF_LSH|BPF_X:
+               op = "lsh";
+               fmt = "x";
+               break;
+
+       case BPF_ALU|BPF_RSH|BPF_X:
+               op = "rsh";
+               fmt = "x";
+               break;
+
+       case BPF_ALU|BPF_ADD|BPF_K:
+               op = "add";
+               fmt = "#%d";
+               break;
+
+       case BPF_ALU|BPF_SUB|BPF_K:
+               op = "sub";
+               fmt = "#%d";
+               break;
+                       
+       case BPF_ALU|BPF_MUL|BPF_K:
+               op = "mul";
+               fmt = "#%d";
+               break;
+                       
+       case BPF_ALU|BPF_DIV|BPF_K:
+               op = "div";
+               fmt = "#%d";
+               break;
+                       
+       case BPF_ALU|BPF_AND|BPF_K:
+               op = "and";
+               fmt = "#%d";
+               break;
+                       
+       case BPF_ALU|BPF_OR|BPF_K:
+               op = "or";
+               fmt = "#%d";
+               break;
+
+       case BPF_ALU|BPF_LSH|BPF_K:
+               op = "lsh";
+               fmt = "#%d";
+               break;
+
+       case BPF_ALU|BPF_RSH|BPF_K:
+               op = "rsh";
+               fmt = "#%d";
+               break;
+
+       case BPF_ALU|BPF_NEG:
+               op = "neg";
+               fmt = "";
+               break;
+
+       case BPF_MISC|BPF_TAX:
+               op = "tax";
+               fmt = "";
+               break;
+
+       case BPF_MISC|BPF_TXA:
+               op = "txa";
+               fmt = "";
+               break;
+       }
+       (void)sprintf(operand, fmt, v);
+       (void)sprintf(image,
+                     (BPF_CLASS(p->code) == BPF_JMP && 
+                      BPF_OP(p->code) != BPF_JA) ?
+                     "(%03d) %-8s %-16s jt %d\tjf %d"
+                     : "(%03d) %-8s %s",
+                     n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
+       return image;
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/etherent.c b/usr/src/contrib/tcpdump/tcpdump/etherent.c
new file mode 100644 (file)
index 0000000..9d7ee80
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: etherent.c,v 1.2 90/09/20 23:16:06 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "interface.h"
+
+#ifndef ETHER_SERVICE
+
+#include "etherent.h"
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+       if (isdigit(c))
+               return c - '0';
+       else if (islower(c))
+               return c - 'a' + 10;
+       else
+               return c - 'A' + 10;
+}
+
+static inline int
+skip_space(f)
+       FILE *f;
+{
+       int c;
+
+       do {
+               c = getc(f);
+       } while (isspace(c) && c != '\n');
+
+       return c;
+}
+
+static inline int
+skip_line(f)
+       FILE *f;
+{
+       int c;
+
+       do
+               c = getc(f);
+       while (c != '\n' && c != EOF);
+
+       return c;
+}
+
+struct etherent *
+next_etherent(fp)
+       FILE *fp;
+{
+       register int c, d, i;
+       char *bp;
+       static struct etherent e;
+       static int nline = 1;
+ top:
+       while (nline) {
+               /* Find addr */
+               c = skip_space(fp);
+               if (c == '\n')
+                       continue;
+               /* If this is a comment, or first thing on line
+                  cannot be etehrnet address, skip the line. */
+               else if (!isxdigit(c))
+                       c = skip_line(fp);
+               else {
+                       /* must be the start of an address */
+                       for (i = 0; i < 6; i += 1) {
+                               d = xdtoi(c);
+                               c = getc(fp);
+                               if (c != ':') {
+                                       d <<= 4;
+                                       d |= xdtoi(c);
+                                       c = getc(fp);
+                               }
+                               e.addr[i] = d;
+                               if (c != ':')
+                                       break;
+                               c = getc(fp);
+                       }
+                       nline = 0;
+               }
+               if (c == EOF)
+                       return 0;
+       }
+       
+       /* If we started a new line, 'c' holds the char past the ether addr,
+          which we assume is white space.  If we are continuning a line,
+          'c' is garbage.  In either case, we can throw it away. */
+          
+       c = skip_space(fp);
+       if (c == '\n') {
+               nline = 1;
+               goto top;
+       }
+       else if (c == '#') {
+               (void)skip_line(fp);
+               nline = 1;
+               goto top;
+       }
+       else if (c == EOF)
+               return 0;
+       
+       /* Must be a name. */
+       bp = e.name;
+       /* Use 'd' to prevent buffer overflow. */
+       d = sizeof(e.name) - 1;
+       do {
+               *bp++ = c;
+               c = getc(fp);
+       } while (!isspace(c) && c != EOF && --d > 0);
+       *bp = '\0';
+       if (c == '\n')
+               nline = 1;
+
+       return &e;
+}
+
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/etherent.h b/usr/src/contrib/tcpdump/tcpdump/etherent.h
new file mode 100644 (file)
index 0000000..83ebaab
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: etherent.h,v 1.2 90/09/20 23:16:17 mccanne Exp $ (LBL)
+ */
+
+/* File name of ethernet address data base. */
+
+#define ETHERS_FILE "/etc/ethers"
+
+struct etherent {
+       u_char addr[6];
+       char name[122];
+};
+
+struct etherent *next_etherent();
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/etherproto.h b/usr/src/contrib/tcpdump/tcpdump/etherproto.h
new file mode 100644 (file)
index 0000000..5c0e245
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: etherproto.h,v 1.7 90/10/10 15:04:04 mccanne Exp $ (LBL)
+ */
+
+/* Map between Ethernet protocol types and names */
+
+/* Add other Ethernet packet types here */
+#ifndef        ETHERTYPE_SPRITE
+#define        ETHERTYPE_SPRITE        0x0500
+#endif
+#ifndef        ETHERTYPE_MOPDL
+#define        ETHERTYPE_MOPDL         0x6001
+#endif
+#ifndef        ETHERTYPE_MOPRC
+#define        ETHERTYPE_MOPRC         0x6002
+#endif
+#ifndef        ETHERTYPE_DN
+#define        ETHERTYPE_DN            0x6003
+#endif
+#ifndef        ETHERTYPE_LAT
+#define        ETHERTYPE_LAT           0x6004
+#endif
+#ifndef        ETHERTYPE_LANBRIDGE
+#define        ETHERTYPE_LANBRIDGE     0x8038
+#endif
+#ifndef        ETHERTYPE_VEXP
+#define        ETHERTYPE_VEXP          0x805b
+#endif
+#ifndef        ETHERTYPE_VPROD
+#define        ETHERTYPE_VPROD         0x805c
+#endif
+#ifndef        ETHERTYPE_LOOPBACK
+#define        ETHERTYPE_LOOPBACK      0x9000
+#endif
+
+#ifndef ETHERTYPE_ATALK
+#define ETHERTYPE_ATALK                0x809b /* XXX */
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP         0x80f3
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS           0x0600
+#endif
+
+struct eproto {
+       char *s;
+       u_short p;
+};
+
+extern struct eproto eproto_db[];
diff --git a/usr/src/contrib/tcpdump/tcpdump/extract.h b/usr/src/contrib/tcpdump/tcpdump/extract.h
new file mode 100644 (file)
index 0000000..bd45c59
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: extract.h,v 1.4 92/05/25 14:28:36 mccanne Exp $ (LBL)
+ */
+
+#ifdef TCPDUMP_ALIGN
+#if BYTEORDER == LITTLE_ENDIAN
+#define EXTRACT_SHORT(p)\
+       ((u_short)\
+               ((u_short)*((u_char *)p+1)<<8|\
+                (u_short)*((u_char *)p+0)<<0))
+#define EXTRACT_LONG(p)\
+               ((u_long)*((u_char *)p+3)<<24|\
+                (u_long)*((u_char *)p+2)<<16|\
+                (u_long)*((u_char *)p+1)<<8|\
+                (u_long)*((u_char *)p+0)<<0)
+#else
+#define EXTRACT_SHORT(p)\
+       ((u_short)\
+               ((u_short)*((u_char *)p+0)<<8|\
+                (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+               ((u_long)*((u_char *)p+0)<<24|\
+                (u_long)*((u_char *)p+1)<<16|\
+                (u_long)*((u_char *)p+2)<<8|\
+                (u_long)*((u_char *)p+3)<<0)
+#endif
+#else
+#define EXTRACT_SHORT(p)       ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p)                (ntohl(*(u_long *)p))
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/gencode.c b/usr/src/contrib/tcpdump/tcpdump/gencode.c
new file mode 100644 (file)
index 0000000..8cb48ea
--- /dev/null
@@ -0,0 +1,1384 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: gencode.c,v 1.33 92/05/22 16:38:39 mccanne Exp $ (LBL)";
+#endif
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "gencode.h"
+#include "nametoaddr.h"
+#include "extract.h"
+
+#define JMP(c) ((c)|BPF_JMP|BPF_K)
+
+extern struct bpf_insn *icode_to_fcode();
+extern u_long net_mask();
+static void init_linktype();
+
+static int alloc_reg();
+static void free_reg();
+
+static struct block *root;
+
+/*
+ * We divy out chunks of memory rather than call malloc each time so
+ * we don't have to worry about leaking memory.  It's probably
+ * not a big deal if all this memory was wasted but it this ever
+ * goes into a library that would probably not be a good idea.
+ */
+#define NCHUNKS 16
+#define CHUNK0SIZE 1024
+struct chunk {
+       u_int n_left;
+       void *m;
+};
+
+static struct chunk chunks[NCHUNKS];
+static int cur_chunk;
+
+static void *
+newchunk(n)
+       u_int n;
+{
+       struct chunk *cp;
+       int k, size;
+       
+       /* XXX Round up to nearest long. */
+       n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+
+       cp = &chunks[cur_chunk];
+       if (n > cp->n_left) {
+               ++cp, k = ++cur_chunk;
+               if (k >= NCHUNKS)
+                       error("out of memory");
+               size = CHUNK0SIZE << k;
+               cp->m = (void *)malloc(size);
+               bzero((char *)cp->m, size);
+               cp->n_left = size;
+               if (n > size)
+                       error("out of memory");
+       }
+       cp->n_left -= n;
+       return (void *)((char *)cp->m + cp->n_left);
+}
+
+static void
+freechunks()
+{
+       int i;
+
+       for (i = 0; i < NCHUNKS; ++i)
+               if (chunks[i].m)
+                       free(chunks[i].m);
+}
+
+static inline struct block *
+new_block(code)
+       int code;
+{
+       struct block *p;
+
+       p = (struct block *)newchunk(sizeof(*p));
+       p->s.code = code;
+       p->head = p;
+
+       return p;
+}
+
+static inline struct slist *
+new_stmt(code)
+       int code;
+{
+       struct slist *p;
+
+       p = (struct slist *)newchunk(sizeof(*p));
+       p->s.code = code;
+
+       return p;
+}
+
+static struct block *
+gen_retblk(v)
+       int v;
+{
+       struct block *b = new_block(BPF_RET|BPF_K);
+
+       b->s.k = v;
+       return b;
+}
+
+static inline void
+syntax()
+{
+       error("syntax error in filter expression");
+}
+
+static u_long netmask;
+
+struct bpf_program *
+parse(buf, Oflag, linktype, mask)
+       char *buf;
+       int Oflag;
+       int linktype;
+       u_long mask;
+{
+       extern int n_errors;
+       static struct bpf_program F;
+       struct bpf_insn *p;
+       int len;
+
+       netmask = mask;
+
+       F.bf_insns = 0;
+       F.bf_len = 0;
+
+       lex_init(buf ? buf : "");
+       init_linktype(linktype);
+       yyparse();
+
+       if (n_errors)
+               syntax();
+
+       if (root == 0)
+               root = gen_retblk(snaplen);
+
+       if (Oflag) {
+               optimize(&root);
+               if (root == 0 || 
+                   (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
+                       error("expression rejects all packets");
+       }
+       p = icode_to_fcode(root, &len);
+       F.bf_insns = p;
+       F.bf_len  = len;
+
+       freechunks();
+       return &F;
+}
+
+/*
+ * Backpatch the blocks in 'list' to 'target'.  The 'sense' field indicates
+ * which of the jt and jf fields has been resolved and which is a pointer
+ * back to another unresolved block (or nil).  At least one of the fields
+ * in each block is already resolved.
+ */
+static void
+backpatch(list, target)
+       struct block *list, *target;
+{
+       struct block *next;
+
+       while (list) {
+               if (!list->sense) {
+                       next = JT(list);
+                       JT(list) = target;
+               } else {
+                       next = JF(list);
+                       JF(list) = target;
+               }
+               list = next;
+       }
+}
+
+/*
+ * Merge the lists in b0 and b1, using the 'sense' field to indicate
+ * which of jt and jf is the link.
+ */
+static void
+merge(b0, b1)
+       struct block *b0, *b1;
+{
+       register struct block **p = &b0;
+
+       /* Find end of list. */
+       while (*p)
+               p = !((*p)->sense) ? &JT(*p) : &JF(*p);
+
+       /* Concatenate the lists. */
+       *p = b1;
+}
+
+void
+finish_parse(p)
+       struct block *p;
+{
+       backpatch(p, gen_retblk(snaplen));
+       p->sense = !p->sense;
+       backpatch(p, gen_retblk(0));
+       root = p->head;
+}
+
+void
+gen_and(b0, b1)
+       struct block *b0, *b1;
+{
+       backpatch(b0, b1->head);
+       b0->sense = !b0->sense;
+       b1->sense = !b1->sense;
+       merge(b1, b0);
+       b1->sense = !b1->sense;
+       b1->head = b0->head;
+}
+
+void
+gen_or(b0, b1)
+       struct block *b0, *b1;
+{
+       b0->sense = !b0->sense;
+       backpatch(b0, b1->head);
+       b0->sense = !b0->sense;
+       merge(b1, b0);
+       b1->head = b0->head;
+}
+
+void
+gen_not(b)
+       struct block *b;
+{
+       b->sense = !b->sense;
+}
+
+static struct block *
+gen_cmp(offset, size, v)
+       u_int offset, size;
+       long v;
+{
+       struct slist *s;
+       struct block *b;
+
+       s = new_stmt(BPF_LD|BPF_ABS|size);
+       s->s.k = offset;
+
+       b = new_block(JMP(BPF_JEQ));
+       b->stmts = s;
+       b->s.k = v;
+
+       return b;
+}
+
+struct block *
+gen_mcmp(offset, size, v, mask)
+       u_int offset, size;
+       long v;
+       u_long mask;
+{
+       struct block *b = gen_cmp(offset, size, v);
+       struct slist *s;
+
+       if (mask != 0xffffffff) {
+               s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+               s->s.k = mask;
+               b->stmts->next = s;
+       }
+       return b;
+}
+
+struct block *
+gen_bcmp(offset, size, v)
+       u_int offset;
+       u_int size;
+       u_char *v;
+{
+       struct block *b, *tmp;
+       int k;
+
+       b = 0;
+       while (size >= 4) {
+               k = size - 4;
+               tmp = gen_cmp(offset + k, BPF_W, EXTRACT_LONG(&v[k]));
+               if (b != 0)
+                       gen_and(b, tmp);
+               b = tmp;
+               size -= 4;
+       }
+       while (size >= 2) {
+               k = size - 2;
+               tmp = gen_cmp(offset + k, BPF_H, (long)EXTRACT_SHORT(&v[k]));
+               if (b != 0)
+                       gen_and(b, tmp);
+               b = tmp;
+               size -= 2;
+       }
+       if (size > 0) {
+               tmp = gen_cmp(offset, BPF_B, (long)v[0]);
+               if (b != 0)
+                       gen_and(b, tmp);
+               b = tmp;
+       }
+       return b;
+}
+
+/*
+ * Various code contructs need to know the layout of the data link
+ * layer.  These variables give the necessary offsets.  off_linktype
+ * is set to -1 for no encapsulation, in which case, IP is assumed.
+ */
+static u_int off_linktype;
+static u_int off_nl;
+static int linktype;
+
+static void
+init_linktype(type)
+       int type;
+{
+       linktype = type;
+
+       switch (type) {
+
+       case DLT_EN10MB:
+               off_linktype = 12;
+               off_nl = 14;
+               return;
+
+       case DLT_SLIP:
+               /*
+                * SLIP doesn't have a link level type.  The 16 byte
+                * header is hacked into our SLIP driver.
+                */
+               off_linktype = -1;
+               off_nl = 16;
+               return;
+
+       case DLT_NULL:
+               off_linktype = -1;
+               off_nl = 0;
+               return;
+
+       case DLT_PPP:
+               off_linktype = 2;
+               off_nl = 4;
+               return;
+
+       case DLT_FDDI:
+               off_linktype = 19;
+               off_nl = 21;
+               return;
+
+       case DLT_IEEE802:
+               off_linktype = 20;
+               off_nl = 22;
+               return;
+       }
+       error("unknown data link type 0x%x", linktype);
+       /* NOTREACHED */
+}
+
+static struct block *
+gen_uncond(rsense)
+       int rsense;
+{
+       struct block *b;
+       struct slist *s;
+
+       s = new_stmt(BPF_LD|BPF_IMM);
+       s->s.k = !rsense;
+       b = new_block(JMP(BPF_JEQ));
+       b->stmts = s;
+
+       return b;
+}
+
+static inline struct block *
+gen_true()
+{
+       return gen_uncond(1);
+}
+
+static inline struct block *
+gen_false()
+{
+       return gen_uncond(0);
+}
+
+struct block *
+gen_linktype(proto)
+       int proto;
+{
+       switch (linktype) {
+       case DLT_SLIP:
+               if (proto == ETHERTYPE_IP)
+                       return gen_true();
+               else
+                       return gen_false();
+
+       case DLT_PPP:
+               if (proto == ETHERTYPE_IP)
+                       proto = 0x0021;         /* XXX - need ppp.h defs */
+               break;
+       }
+       return gen_cmp(off_linktype, BPF_H, (long)proto);
+}
+
+static struct block *
+gen_hostop(addr, mask, dir, proto, src_off, dst_off)
+       u_long addr;
+       u_long mask;
+       int dir, proto;
+       u_int src_off, dst_off;
+{
+       struct block *b0, *b1;
+       u_int offset;
+
+       switch (dir) {
+
+       case Q_SRC:
+               offset = src_off;
+               break;
+
+       case Q_DST:
+               offset = dst_off;
+               break;
+
+       case Q_AND:
+               b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+               b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+               gen_and(b0, b1);
+               return b1;
+
+       case Q_OR:
+       case Q_DEFAULT:
+               b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+               b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+               gen_or(b0, b1);
+               return b1;
+
+       default:
+               abort();
+       }
+       b0 = gen_linktype(proto);
+       b1 = gen_mcmp(offset, BPF_W, (long)addr, mask);
+       gen_and(b0, b1);
+       return b1;
+}
+
+static struct block *
+gen_ehostop(eaddr, dir)
+       u_char *eaddr;
+       int dir;
+{
+       struct block *b0, *b1;
+
+       switch (dir) {
+       case Q_SRC:
+               return gen_bcmp(6, 6, eaddr);
+
+       case Q_DST:
+               return gen_bcmp(0, 6, eaddr);
+
+       case Q_AND:
+               b0 = gen_ehostop(eaddr, Q_SRC);
+               b1 = gen_ehostop(eaddr, Q_DST);
+               gen_and(b0, b1);
+               return b1;
+               
+       case Q_DEFAULT:
+       case Q_OR:
+               b0 = gen_ehostop(eaddr, Q_SRC);
+               b1 = gen_ehostop(eaddr, Q_DST);
+               gen_or(b0, b1);
+               return b1;
+       }
+       abort();
+       /* NOTREACHED */
+}
+
+static struct block *
+gen_host(addr, mask, proto, dir)
+       u_long addr;
+       u_long mask;
+       int proto;
+       int dir;
+{
+       struct block *b0, *b1;
+
+       switch (proto) {
+
+       case Q_DEFAULT:
+               b0 = gen_host(addr, mask, Q_IP, dir);
+               b1 = gen_host(addr, mask, Q_ARP, dir);
+               gen_or(b0, b1);
+               b0 = gen_host(addr, mask, Q_RARP, dir);
+               gen_or(b1, b0);
+               return b0;
+
+       case Q_IP:
+               return gen_hostop(addr, mask, dir, ETHERTYPE_IP, 
+                                 off_nl + 12, off_nl + 16);
+
+       case Q_RARP:
+               return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP,
+                                 off_nl + 14, off_nl + 24);
+
+       case Q_ARP:
+               return gen_hostop(addr, mask, dir, ETHERTYPE_ARP,
+                                 off_nl + 14, off_nl + 24);
+
+       case Q_TCP:
+               error("'tcp' modifier applied to host");
+
+       case Q_UDP:
+               error("'udp' modifier applied to host");
+
+       case Q_ICMP:
+               error("'icmp' modifier applied to host");
+       }
+       abort();
+       /* NOTREACHED */
+}
+
+static struct block *
+gen_gateway(eaddr, alist, proto, dir)
+       u_char *eaddr;
+       u_long **alist;
+       int proto;
+       int dir;
+{
+       struct block *b0, *b1, *tmp;
+
+       if (dir != 0)
+               error("direction applied to 'gateway'");
+
+       switch (proto) {
+       case Q_DEFAULT:
+       case Q_IP:
+       case Q_ARP:
+       case Q_RARP:
+               b0 = gen_ehostop(eaddr, Q_OR);
+               b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+               while (*alist) {
+                       tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+                       gen_or(b1, tmp);
+                       b1 = tmp;
+               }
+               gen_not(b1);
+               gen_and(b0, b1);
+               return b1;
+       }
+       error("illegal modifier of 'gateway'");
+       /* NOTREACHED */
+}
+
+struct block *
+gen_proto_abbrev(proto)
+       int proto;
+{
+       struct block *b0, *b1;
+
+       switch (proto) {
+
+       case Q_TCP:
+               b0 = gen_linktype(ETHERTYPE_IP);
+               b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_TCP);
+               gen_and(b0, b1);
+               break;
+               
+       case Q_UDP:
+               b0 =  gen_linktype(ETHERTYPE_IP);
+               b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_UDP);
+               gen_and(b0, b1);
+               break;
+
+       case Q_ICMP:
+               b0 =  gen_linktype(ETHERTYPE_IP);
+               b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_ICMP);
+               gen_and(b0, b1);
+               break;
+
+       case Q_IP:
+               b1 =  gen_linktype(ETHERTYPE_IP);
+               break;
+
+       case Q_ARP:
+               b1 =  gen_linktype(ETHERTYPE_ARP);
+               break;
+
+       case Q_RARP:
+               b1 =  gen_linktype(ETHERTYPE_REVARP);
+               break;
+
+       case Q_LINK:
+               error("link layer applied in wrong context");
+
+       default:
+               abort();
+       }
+       return b1;
+}
+
+static struct block *
+gen_ipfrag()
+{
+       struct slist *s;
+       struct block *b;
+
+       /* not ip frag */
+       s = new_stmt(BPF_LD|BPF_H|BPF_ABS);
+       s->s.k = off_nl + 6;
+       b = new_block(JMP(BPF_JSET));
+       b->s.k = 0x1fff;
+       b->stmts = s;
+       gen_not(b);
+
+       return b;
+}
+
+static struct block *
+gen_portatom(off, v)
+       int off;
+       long v;
+{
+       struct slist *s;
+       struct block *b;
+
+       s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+       s->s.k = off_nl;
+
+       s->next = new_stmt(BPF_LD|BPF_IND|BPF_H);
+       s->next->s.k = off_nl + off;
+
+       b = new_block(JMP(BPF_JEQ));
+       b->stmts = s;
+       b->s.k = v;
+
+       return b;
+}
+
+struct block *
+gen_portop(port, proto, dir)
+       int port;
+       int proto;
+       int dir;
+{
+       struct block *b0, *b1, *tmp;
+
+       /* ip proto 'proto' */
+       tmp = gen_cmp(off_nl + 9, BPF_B, (long)proto);
+       b0 = gen_ipfrag();
+       gen_and(tmp, b0);
+
+       switch (dir) {
+       case Q_SRC:
+               b1 = gen_portatom(0, (long)port);
+               break;
+
+       case Q_DST:
+               b1 = gen_portatom(2, (long)port);
+               break;
+
+       case Q_OR:
+       case Q_DEFAULT:
+               tmp = gen_portatom(0, (long)port);
+               b1 = gen_portatom(2, (long)port);
+               gen_or(tmp, b1);
+               break;
+
+       case Q_AND:
+               tmp = gen_portatom(0, (long)port);
+               b1 = gen_portatom(2, (long)port);
+               gen_and(tmp, b1);
+               break;
+
+       default:
+               abort();
+       }
+       gen_and(b0, b1);
+
+       return b1;
+}
+
+static struct block *
+gen_port(port, ip_proto, dir)
+       int port;
+       int ip_proto;
+       int dir;
+{
+       struct block *b0, *b1, *tmp;
+
+       /* ether proto ip */
+       b0 =  gen_linktype(ETHERTYPE_IP);
+       
+       switch (ip_proto) {
+       case IPPROTO_UDP:
+       case IPPROTO_TCP:
+               b1 = gen_portop(port, ip_proto, dir);
+               break;
+
+       case PROTO_UNDEF:
+               tmp = gen_portop(port, IPPROTO_TCP, dir);
+               b1 = gen_portop(port, IPPROTO_UDP, dir);
+               gen_or(tmp, b1);
+               break;
+
+       default:
+               abort();
+       }
+       gen_and(b0, b1);
+       return b1;
+}
+
+int
+lookup_proto(name, proto)
+       char *name;
+       int proto;
+{
+       int v;
+
+       switch (proto) {
+       case Q_DEFAULT:
+       case Q_IP:
+               v = s_nametoproto(name);
+               if (v == PROTO_UNDEF)
+                       error("unknown ip proto '%s'", name);
+               break;
+
+       case Q_LINK:
+               /* XXX should look up h/w protocol type based on linktype */
+               v = s_nametoeproto(name);
+               if (v == PROTO_UNDEF)
+                       error("unknown ether proto '%s'", name);
+               break;
+
+       default:
+               v = PROTO_UNDEF;
+               break;
+       }
+       return v;
+}
+
+struct block *
+gen_proto(v, proto, dir)
+       int v;
+       int proto;
+       int dir;
+{
+       struct block *b0, *b1;
+
+       if (dir != Q_DEFAULT)
+               error("direction applied to 'proto'");
+       
+       switch (proto) {
+       case Q_DEFAULT:
+       case Q_IP:
+               b0 = gen_linktype(ETHERTYPE_IP);
+               b1 = gen_cmp(off_nl + 9, BPF_B, (long)v);
+               gen_and(b0, b1);
+               return b1;
+
+       case Q_ARP:
+               error("arp does not encapsulate another protocol");
+               /* NOTREACHED */
+               
+       case Q_RARP:
+               error("rarp does not encapsulate another protocol");
+               /* NOTREACHED */
+
+       case Q_LINK:
+               return gen_linktype(v);
+
+       case Q_UDP:
+               error("'udp proto' is bogus");
+
+       case Q_TCP:
+               error("'tcp proto' is bogus");
+
+       case Q_ICMP:
+               error("'icmp proto' is bogus");
+       }
+       abort();
+       /* NOTREACHED */
+}
+       
+struct block *
+gen_scode(name, q)
+       char *name;
+       struct qual q;
+{
+       int proto = q.proto;
+       int dir = q.dir;
+       u_char *eaddr;
+       u_long mask, addr, **alist;
+       struct block *b, *tmp;
+       int port, real_proto;
+
+       switch (q.addr) {
+
+       case Q_NET:
+               addr = s_nametonetaddr(name);
+               if (addr == 0)
+                       error("unknown network '%s'", name);
+               mask = net_mask(&addr);
+               return gen_host(addr, mask, proto, dir);
+
+       case Q_DEFAULT:
+       case Q_HOST:
+               if (proto == Q_LINK) {
+                       /* XXX Should lookup hw addr based on link layer */
+                       eaddr = ETHER_hostton(name);
+                       if (eaddr == 0)
+                               error("unknown ether host '%s'", name);
+                       return gen_ehostop(eaddr, dir);
+
+               } else {
+                       alist = s_nametoaddr(name);
+                       if (alist == 0 || *alist == 0)
+                               error("uknown host '%s'", name);
+                       b = gen_host(**alist++, 0xffffffffL, proto, dir);
+                       while (*alist) {
+                               tmp = gen_host(**alist++, 0xffffffffL, 
+                                              proto, dir);
+                               gen_or(b, tmp);
+                               b = tmp;
+                       }
+                       return b;
+               }
+
+       case Q_PORT: 
+               if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP)
+                       error("illegal qualifier of 'port'");
+               if (s_nametoport(name, &port, &real_proto) == 0)
+                       error("unknown port '%s'", name);
+               if (proto == Q_UDP) {
+                       if (real_proto == IPPROTO_TCP)
+                               error("port '%s' is tcp", name);
+                       else
+                               /* override PROTO_UNDEF */
+                               real_proto = IPPROTO_UDP;
+               }
+               if (proto == Q_TCP) {
+                       if (real_proto == IPPROTO_UDP)
+                               error("port '%s' is udp", name);
+                       else
+                               /* override PROTO_UNDEF */
+                               real_proto = IPPROTO_TCP;
+               }
+               return gen_port(port, real_proto, dir);
+
+       case Q_GATEWAY:
+               eaddr = ETHER_hostton(name);
+               if (eaddr == 0)
+                       error("unknown ether host: %s", name);
+                       
+               alist = s_nametoaddr(name);
+               if (alist == 0 || *alist == 0)
+                       error("uknown host '%s'", name);
+               return gen_gateway(eaddr, alist, proto, dir);
+
+       case Q_PROTO:
+               real_proto = lookup_proto(name, proto);
+               if (real_proto >= 0)
+                       return gen_proto(real_proto, proto, dir);
+               else
+                       error("unknown protocol: %s", name);
+
+       case Q_UNDEF:
+               syntax();
+               /* NOTREACHED */
+       }
+       abort();
+       /* NOTREACHED */
+}
+
+struct block *
+gen_ncode(v, q)
+       u_long v;
+       struct qual q;
+{
+       u_long mask;
+       int proto = q.proto;
+       int dir = q.dir;
+
+       switch (q.addr) {
+
+       case Q_DEFAULT:
+       case Q_HOST:
+       case Q_NET:
+               mask = net_mask(&v);
+               return gen_host(v, mask, proto, dir);
+
+       case Q_PORT:
+               if (proto == Q_UDP)
+                       proto = IPPROTO_UDP;
+               else if (proto == Q_TCP)
+                       proto = IPPROTO_TCP;
+               else if (proto == Q_DEFAULT)
+                       proto = PROTO_UNDEF;
+               else
+                       error("illegal qualifier of 'port'");
+
+               return gen_port((int)v, proto, dir);
+
+       case Q_GATEWAY:
+               error("'gateway' requires a name");
+               /* NOTREACHED */
+
+       case Q_PROTO:
+               return gen_proto((int)v, proto, dir);
+
+       case Q_UNDEF:
+               syntax();
+               /* NOTREACHED */
+       }
+       abort();
+       /* NOTREACHED */
+}
+
+struct block *
+gen_ecode(eaddr, q)
+       u_char *eaddr;
+       struct qual q;
+{
+       if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK)
+               return gen_ehostop(eaddr, (int)q.dir);
+       else 
+               error("ethernet address used in non-ether expression");
+       /* NOTREACHED */
+}
+
+void
+sappend(s0, s1)
+       struct slist *s0, *s1;
+{
+       /*
+        * This is definitely not the best way to do this, but the
+        * lists will rarely get long.
+        */
+       while (s0->next)
+               s0 = s0->next;
+       s0->next = s1;
+}
+
+struct slist *
+xfer_to_x(a)
+       struct arth *a;
+{
+       struct slist *s;
+
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = a->regno;
+       return s;
+}
+
+struct slist *
+xfer_to_a(a)
+       struct arth *a;
+{
+       struct slist *s;
+
+       s = new_stmt(BPF_LD|BPF_MEM);
+       s->s.k = a->regno;
+       return s;
+}
+
+struct arth *
+gen_load(proto, index, size)
+       int proto;
+       struct arth *index;
+       int size;
+{
+       struct slist *s, *tmp;
+       struct block *b;
+       int regno = alloc_reg();
+
+       free_reg(index->regno);
+       switch (size) {
+
+       default:
+               error("data size must be 1, 2, or 4");
+
+       case 1:
+               size = BPF_B;
+               break;
+
+       case 2:
+               size = BPF_H;
+               break;
+
+       case 4:
+               size = BPF_W;
+               break;
+       }
+       switch (proto) {
+       default:
+               error("unsupported index operation");
+               
+       case Q_LINK:
+               s = xfer_to_x(index);
+               tmp = new_stmt(BPF_LD|BPF_IND|size);
+               sappend(s, tmp);
+               sappend(index->s, s);
+               break;
+
+       case Q_IP:
+       case Q_ARP:
+       case Q_RARP:
+               /* XXX Note that we assume a fixed link link header here. */
+               s = xfer_to_x(index);
+               tmp = new_stmt(BPF_LD|BPF_IND|size);
+               tmp->s.k = off_nl;
+               sappend(s, tmp);
+               sappend(index->s, s);
+
+               b = gen_proto_abbrev(proto);
+               if (index->b)
+                       gen_and(index->b, b);
+               index->b = b;
+               break;
+
+       case Q_TCP:
+       case Q_UDP:
+       case Q_ICMP:
+               s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+               s->s.k = off_nl;
+               sappend(s, xfer_to_a(index));
+               sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
+               sappend(s, new_stmt(BPF_MISC|BPF_TAX));
+               sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
+               tmp->s.k = off_nl;
+               sappend(index->s, s);
+               
+               gen_and(gen_proto_abbrev(proto), b = gen_ipfrag());
+               if (index->b)
+                       gen_and(index->b, b);
+               index->b = b;
+               break;
+       }
+       index->regno = regno;
+       s = new_stmt(BPF_ST);
+       s->s.k = regno;
+       sappend(index->s, s);
+
+       return index;
+}
+
+struct block *
+gen_relation(code, a0, a1, reversed)
+       int code;
+       struct arth *a0, *a1;
+       int reversed;
+{
+       struct slist *s0, *s1, *s2;
+       struct block *b, *tmp;
+
+       s0 = xfer_to_x(a1);
+       s1 = xfer_to_a(a0);
+       s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X);
+       b = new_block(JMP(code));
+       if (reversed)
+               gen_not(b);
+
+       sappend(s1, s2);
+       sappend(s0, s1);
+       sappend(a1->s, s0);
+       sappend(a0->s, a1->s);
+
+       b->stmts = a0->s;
+
+       free_reg(a0->regno);
+       free_reg(a1->regno);
+
+       /* 'and' together protocol checks */
+       if (a0->b) {
+               if (a1->b) {
+                       gen_and(a0->b, tmp = a1->b);
+               }
+               else
+                       tmp = a0->b;
+       } else 
+               tmp = a1->b;
+
+       if (tmp)
+               gen_and(tmp, b);
+
+       return b;
+}
+
+struct arth *
+gen_loadlen()
+{
+       int regno = alloc_reg();
+       struct arth *a = (struct arth *)newchunk(sizeof(*a));
+       struct slist *s;
+
+       s = new_stmt(BPF_LD|BPF_LEN);
+       s->next = new_stmt(BPF_ST);
+       s->next->s.k = regno;
+       a->s = s;
+       a->regno = regno;
+
+       return a;
+}
+
+struct arth *
+gen_loadi(val)
+       int val;
+{
+       struct arth *a;
+       struct slist *s;
+       int reg;
+
+       a = (struct arth *)newchunk(sizeof(*a));
+
+       reg = alloc_reg();
+
+       s = new_stmt(BPF_LD|BPF_IMM);
+       s->s.k = val;
+       s->next = new_stmt(BPF_ST);
+       s->next->s.k = reg;
+       a->s = s;
+       a->regno = reg;
+
+       return a;
+}
+
+struct arth *
+gen_neg(a)
+       struct arth *a;
+{
+       struct slist *s;
+
+       s = xfer_to_a(a);
+       sappend(a->s, s);
+       s = new_stmt(BPF_ALU|BPF_NEG);
+       s->s.k = 0;
+       sappend(a->s, s);
+       s = new_stmt(BPF_ST);
+       s->s.k = a->regno;
+       sappend(a->s, s);
+
+       return a;
+}
+
+struct arth *
+gen_arth(code, a0, a1)
+       int code;
+       struct arth *a0, *a1;
+{
+       struct slist *s0, *s1, *s2;
+
+       s0 = xfer_to_x(a1);
+       s1 = xfer_to_a(a0);
+       s2 = new_stmt(BPF_ALU|BPF_X|code);
+
+       sappend(s1, s2);
+       sappend(s0, s1);
+       sappend(a1->s, s0);
+       sappend(a0->s, a1->s);
+       
+       free_reg(a1->regno);
+
+       s0 = new_stmt(BPF_ST);
+       a0->regno = s0->s.k = alloc_reg();
+       sappend(a0->s, s0);
+
+       return a0;
+}
+
+/*
+ * Here we handle simple allocation of the scratch registers.
+ * If too many registers are alloc'd, the allocator punts.
+ */
+static int regused[BPF_MEMWORDS];
+static int curreg;
+
+/*
+ * Return the next free register.
+ */
+static int
+alloc_reg()
+{
+       int n = BPF_MEMWORDS;
+
+       while (--n >= 0) {
+               if (regused[curreg])
+                       curreg = (curreg + 1) % BPF_MEMWORDS;
+               else {
+                       regused[curreg] = 1;
+                       return curreg;
+               }
+       }
+       error("too many registers needed to evaluate expression");
+       /* NOTREACHED */
+}
+
+/*
+ * Return a register to the table so it can
+ * be used later.
+ */
+static void
+free_reg(n)
+       int n;
+{
+       regused[n] = 0;
+}
+
+static struct block *
+gen_len(jmp, n)
+       int jmp;
+       int n;
+{
+       struct slist *s;
+       struct block *b;
+
+       s = new_stmt(BPF_LD|BPF_LEN);
+       s->next = new_stmt(BPF_SUB|BPF_IMM);
+       s->next->s.k = n;
+       b = new_block(JMP(jmp));
+       b->stmts = s;
+
+       return b;
+}
+
+struct block *
+gen_greater(n)
+       int n;
+{
+       return gen_len(BPF_JGE, n);
+}
+
+struct block *
+gen_less(n)
+       int n;
+{
+       struct block *b;
+
+       b = gen_len(BPF_JGT, n);
+       gen_not(b);
+
+       return b;
+}
+
+struct block *
+gen_byteop(op, idx, val)
+       int op;
+       int idx;
+       int val;
+{
+       struct block *b;
+       struct slist *s;
+
+       switch (op) {
+       default:
+               abort();
+
+       case '=':
+               return gen_cmp((u_int)idx, BPF_B, (long)val);
+               
+       case '<':
+               b = gen_cmp((u_int)idx, BPF_B, (long)val);
+               b->s.code = JMP(BPF_JGE);
+               gen_not(b);
+               return b;
+
+       case '>':
+               b = gen_cmp((u_int)idx, BPF_B, (long)val);
+               b->s.code = JMP(BPF_JGT);
+               return b;
+
+       case '|':
+               s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+               break;
+
+       case '&':
+               s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+               break;
+       }
+       s->s.k = val;
+       b = new_block(JMP(BPF_JEQ));
+       b->stmts = s;
+       gen_not(b);
+
+       return b;
+}
+
+struct block *
+gen_broadcast(proto)
+       int proto;
+{
+       u_long hostmask;
+       struct block *b0, *b1, *b2;
+       static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       switch (proto) {
+
+       case Q_DEFAULT:
+       case Q_LINK:
+               if (linktype == DLT_EN10MB)
+                       return gen_ehostop(ebroadcast, Q_DST);
+               error("not a broadcast link");
+               break;
+
+       case Q_IP:
+               b0 = gen_linktype(ETHERTYPE_IP);
+               hostmask = ~netmask;
+               b1 = gen_mcmp(off_nl + 16, BPF_W, (long)0, hostmask);
+               b2 = gen_mcmp(off_nl + 16, BPF_W, 
+                             (long)(~0 & hostmask), hostmask);
+               gen_or(b1, b2);
+               gen_and(b0, b2);
+               return b2;
+       }
+       error("only ether/ip broadcast filters supported");
+}
+
+struct block *
+gen_multicast(proto)
+       int proto;
+{
+       register struct block *b0, *b1, *b2;
+       register struct slist *s;
+
+       switch (proto) {
+
+       case Q_DEFAULT:
+       case Q_LINK:
+               if (linktype != DLT_EN10MB)
+                       break;
+
+               /* ether[0] & 1 != 0 */
+               s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+               s->s.k = 0;
+               b0 = new_block(JMP(BPF_JSET));
+               b0->s.k = 1;
+               b0->stmts = s;
+               return b0;
+
+       case Q_IP:
+               b0 = gen_linktype(ETHERTYPE_IP);
+               b1 = gen_cmp(off_nl + 16, BPF_B, (long)224);
+               b1->s.code = JMP(BPF_JGE);
+               gen_and(b0, b1);
+               return b1;
+       }
+       error("only ether/ip multicast filters supported");
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/gencode.h b/usr/src/contrib/tcpdump/tcpdump/gencode.h
new file mode 100644 (file)
index 0000000..b8f342d
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: gencode.h,v 1.14 92/02/14 15:18:55 mccanne Exp $ (LBL)
+ */
+
+/*
+ * filter.h must be included before this file.
+ */
+
+/* Address qualifers. */
+
+#define Q_HOST         1
+#define Q_NET          2
+#define Q_PORT         3
+#define Q_GATEWAY      4
+#define Q_PROTO                5
+
+/* Protocol qualifiers. */
+
+#define Q_LINK         1
+#define Q_IP           2
+#define Q_ARP          3
+#define Q_RARP         4
+#define Q_TCP          5
+#define Q_UDP          6
+#define Q_ICMP         7
+
+/* Directional qualifers. */
+
+#define Q_SRC          1
+#define Q_DST          2
+#define Q_OR           3
+#define Q_AND          4
+
+#define Q_DEFAULT      0
+#define Q_UNDEF                255
+
+struct stmt {
+       int code;
+       long k;
+};
+
+struct slist {
+       struct stmt s;
+       struct slist *next;
+};
+
+/* 
+ * A bit vector to represent definition sets.  We assume TOT_REGISTERS
+ * is smaller than 8*sizeof(atomset).
+ */
+typedef u_long atomset;
+#define ATOMMASK(n) (1 << (n))
+#define ATOMELEM(d, n) (d & ATOMMASK(n))
+
+/*
+ * An unbounded set.
+ */
+typedef u_long *uset;
+
+/*
+ * Total number of atomic entities, including accumulator (A) and index (X).
+ * We treat all these guys similarly during flow analysis.
+ */
+#define N_ATOMS (BPF_MEMWORDS+2)
+
+struct edge {
+       int id;
+       int code;
+       uset edom;
+       struct block *succ;
+       struct block *pred;
+       struct edge *next;      /* link list of incoming edges for a node */
+};
+
+struct block {
+       int id;
+       struct slist *stmts;    /* side effect stmts */
+       struct stmt s;          /* branch stmt */
+       int mark;
+       int level;
+       int offset;
+       int sense;
+       struct edge et;
+       struct edge ef;
+       struct block *head;
+       struct block *link;     /* link field used by optimizer */
+       uset dom;
+       uset closure;
+       struct edge *in_edges;
+       atomset def, kill;
+       atomset in_use;
+       atomset out_use;
+       long oval;
+       long val[N_ATOMS];
+};
+
+struct arth {
+       struct block *b;        /* protocol checks */
+       struct slist *s;        /* stmt list */
+       int regno;              /* virtual register number of result */
+};
+
+extern struct arth *gen_loadi();
+extern struct arth *gen_load();
+extern struct arth *gen_loadlen();
+extern struct arth *gen_neg();
+extern struct arth *gen_arth();
+
+extern void gen_and();
+extern void gen_or();
+extern void gen_not();
+
+extern struct block *gen_scode();
+extern struct block *gen_ecode();
+extern struct block *gen_ncode();
+extern struct block *gen_proto_abbrev();
+extern struct block *gen_relation();
+extern struct block *gen_less();
+extern struct block *gen_greater();
+extern struct block *gen_byteop();
+extern struct block *gen_broadcast();
+extern struct block *gen_multicast();
+
+extern void optimize();
+
+extern void finish_parse();
+
+struct qual {
+       unsigned char addr;
+       unsigned char proto;
+       unsigned char dir;
+       unsigned char pad;
+};
+
+/* XXX */
+#define JT(b)  ((b)->et.succ)
+#define JF(b)  ((b)->ef.succ)
diff --git a/usr/src/contrib/tcpdump/tcpdump/inet.c b/usr/src/contrib/tcpdump/tcpdump/inet.c
new file mode 100644 (file)
index 0000000..550129e
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static  char rcsid[] =
+    "@(#)$Header: inet.c,v 1.12 92/01/29 12:46:18 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "interface.h"
+
+/* Not all systems have IFF_LOOPBACK */
+#ifdef IFF_LOOPBACK
+#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
+#else
+#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0)
+#endif
+
+/*
+ * Return the name of a network interface attached to the system, or 0
+ * if none can be found.  The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+lookup_device()
+{
+       struct ifreq ibuf[16], *ifrp, *ifend, *mp;
+       struct ifconf ifc;
+       int fd;
+       int minunit, n;
+       char *cp;
+       static char device[sizeof(ifrp->ifr_name)];
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               perror("tcpdump: socket");
+               exit(1);
+       }
+       ifc.ifc_len = sizeof ibuf;
+       ifc.ifc_buf = (caddr_t)ibuf;
+
+       if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+           ifc.ifc_len < sizeof(struct ifreq)) {
+               perror("tcpdump: SIOCGIFCONF: ");
+               exit(1);
+       }
+       ifrp = ibuf;
+       ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+       
+       mp = 0;
+       minunit = 666;
+       while (ifrp < ifend) {
+               struct ifreq ifr;
+               /*
+                * Need a template to preserve address info that is
+                * used below to locate the next entry.  (Otherwise,
+                * SIOCGIFFLAGS stomps over it because the requests
+                * are returned in a union.)
+                */
+               bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+               if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+                       fprintf(stderr, "tcpdump: SIOCGIFFLAGS: ");
+                       perror(ifrp->ifr_name);
+                       exit(1);
+               }
+               if ((ifr.ifr_flags & IFF_UP) && !ISLOOPBACK(&ifr)) {
+                       for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+                               ;
+                       n = atoi(cp);
+                       if (n < minunit) {
+                               minunit = n;
+                               mp = ifrp;
+                       }
+               }
+#if BSD >= 199006
+               n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+               if (n < sizeof(*ifrp))
+                       ++ifrp;
+               else
+                       ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+               ++ifrp;
+#endif
+       }
+       close(fd);
+       if (mp == 0)
+               return (0);
+       
+       (void)strcpy(device, mp->ifr_name);
+       return (device);
+}
+
+/*
+ * Get the netmask of an IP address.  This routine is used if
+ * SIOCGIFNETMASK doesn't work.
+ */
+static u_long
+ipaddrtonetmask(addr)
+       u_long addr;
+{
+       if (IN_CLASSA(addr))
+               return (IN_CLASSA_NET);
+       if (IN_CLASSB(addr))
+               return (IN_CLASSB_NET);
+       if (IN_CLASSC(addr))
+               return (IN_CLASSC_NET);
+       error("unknown IP address class: %08X", addr);
+       /* NOTREACHED */
+}
+
+void
+lookup_net(device, netp, maskp)
+       char *device;
+       u_long *netp;
+       u_long *maskp;
+{
+       int fd;
+       struct ifreq ifr;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+
+       /* Use data gram socket to get IP address. */
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror("tcpdump: socket");
+               exit(1);
+       }
+       (void)strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+       if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+               /*
+                * This will fail if an IP address hasn't been assigned.
+                */
+               *netp = 0;
+               *maskp = 0;
+               return;
+       }
+       *netp = sin->sin_addr.s_addr;
+       if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0)
+               *maskp = 0;
+       else
+               *maskp = sin->sin_addr.s_addr;
+       if (*maskp == 0)
+               *maskp = ipaddrtonetmask(*netp);
+       *netp &= *maskp;
+       (void)close(fd);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/interface.h b/usr/src/contrib/tcpdump/tcpdump/interface.h
new file mode 100644 (file)
index 0000000..dfccba6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: interface.h,v 1.46 92/06/02 17:57:22 mccanne Exp $ (LBL)
+ */
+
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+#include "os.h"                        /* operating system stuff */
+#include "md.h"                        /* machine dependent stuff */
+
+#ifndef __STDC__
+extern char *malloc();
+extern char *calloc();
+#endif
+
+extern int dflag;              /* print filter code */
+extern int eflag;              /* print ethernet header */
+extern int nflag;              /* leave addresses as numbers */
+extern int Nflag;              /* remove domains from printed host names */
+extern int qflag;              /* quick (shorter) output */
+extern int Sflag;              /* print raw TCP sequence numbers */
+extern int tflag;              /* print packet arrival time */
+extern int vflag;              /* verbose */
+extern int xflag;              /* print packet in hex */
+
+extern char *program_name;     /* used to generate self-identifying messages */
+
+extern int snaplen;
+/* global pointers to beginning and end of current packet (during printing) */
+extern unsigned char *packetp;
+extern unsigned char *snapend;
+
+extern long thiszone;                  /* gmt to local correction */
+
+extern void ts_print();
+extern int clock_sigfigs();
+
+extern char *lookup_device();
+
+extern void error();
+extern void warning();
+
+extern char *read_infile();
+extern char *copy_argv();
+
+extern void usage();
+extern void show_code();
+extern void init_addrtoname();
+
+/* The printer routines. */
+
+extern void ether_if_print();
+extern void arp_print();
+extern void ip_print();
+extern void tcp_print();
+extern void udp_print();
+extern void icmp_print();
+extern void default_print();
+
+extern void ntp_print();
+extern void nfsreq_print();
+extern void nfsreply_print();
+extern void ns_print();
+extern void ddp_print();
+extern void rip_print();
+extern void tftp_print();
+extern void bootp_print();
+extern void snmp_print();
+extern void sl_if_print();
+extern void ppp_if_print();
+extern void fddi_if_print();
+extern void null_if_print();
+extern void egp_print();
+
+#define min(a,b) ((a)>(b)?(b):(a))
+#define max(a,b) ((b)>(a)?(b):(a))
+
+/* 
+ * The default snapshot length.  This value allows most printers to print
+ * useful information while keeping the amount of unwanted data down.
+ * In particular, it allows for an ethernet header, tcp/ip header, and
+ * 14 bytes of data (assuming no ip options).
+ */
+#define DEFAULT_SNAPLEN 68
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/md.c b/usr/src/contrib/tcpdump/tcpdump/md.c
new file mode 100644 (file)
index 0000000..6bb04b7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: md-vax.c,v 1.3 90/10/03 14:14:33 mccanne Locked $ (LBL)";
+#endif
+
+/* Vaxen appear to have clocks accurate to 1 us,
+   but packetfilter is timestamping to 10 ms. */
+
+int
+clock_sigfigs()
+{
+       return 2;
+}
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/md.h b/usr/src/contrib/tcpdump/tcpdump/md.h
new file mode 100644 (file)
index 0000000..f83d81f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: md-vax.h,v 1.2 90/09/21 02:23:16 mccanne Exp $ (LBL)
+ */
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+/* These should be fixed to be real macros, for speed */
+
+#ifndef NTOHL
+#define NTOHL(x)       (x) = ntohl(x)
+#define NTOHS(x)       (x) = ntohs(x)
+#define HTONL(x)       (x) = htonl(x)
+#define HTONS(x)       (x) = htons(x)
+#endif
+
+#ifndef        vax
+/* Some Ultrix header files may need this */
+#define        vax     1
+#endif vax
diff --git a/usr/src/contrib/tcpdump/tcpdump/mib.h b/usr/src/contrib/tcpdump/tcpdump/mib.h
new file mode 100644 (file)
index 0000000..a81897c
--- /dev/null
@@ -0,0 +1,1256 @@
+/*
+ * This file was generated by tcpdump/makemib on Wed Sep 26 12:12:31 EDT 1990
+ * You probably don't want to edit this by hand!
+ *
+ * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer 
+};
+ */
+
+/* parse problem: new name "mib" for mgmt.mib(1) ignored */
+/* parse problem: no parent for 0.nullSpecific(0) */
+struct obj
+_proteon_obj = {
+       "proteon", 1, 0,
+       NULL, NULL
+},
+_ibm_obj = {
+       "ibm", 2, 0,
+       NULL, &_proteon_obj
+},
+_cmu_obj = {
+       "cmu", 3, 0,
+       NULL, &_ibm_obj
+},
+_unix_obj = {
+       "unix", 4, 0,
+       NULL, &_cmu_obj
+},
+_acc_obj = {
+       "acc", 5, 0,
+       NULL, &_unix_obj
+},
+_twg_obj = {
+       "twg", 6, 0,
+       NULL, &_acc_obj
+},
+_cayman_obj = {
+       "cayman", 7, 0,
+       NULL, &_twg_obj
+},
+_nysernet_obj = {
+       "nysernet", 8, 0,
+       NULL, &_cayman_obj
+},
+_cisco_obj = {
+       "cisco", 9, 0,
+       NULL, &_nysernet_obj
+},
+_nsc_obj = {
+       "nsc", 10, 0,
+       NULL, &_cisco_obj
+},
+_hp_obj = {
+       "hp", 11, 0,
+       NULL, &_nsc_obj
+},
+_epilogue_obj = {
+       "epilogue", 12, 0,
+       NULL, &_hp_obj
+},
+_utennessee_obj = {
+       "utennessee", 13, 0,
+       NULL, &_epilogue_obj
+},
+_bbn_obj = {
+       "bbn", 14, 0,
+       NULL, &_utennessee_obj
+},
+_xylogics_obj = {
+       "xylogics", 15, 0,
+       NULL, &_bbn_obj
+},
+_unisys_obj = {
+       "unisys", 16, 0,
+       NULL, &_xylogics_obj
+},
+_canstar_obj = {
+       "canstar", 17, 0,
+       NULL, &_unisys_obj
+},
+_wellfleet_obj = {
+       "wellfleet", 18, 0,
+       NULL, &_canstar_obj
+},
+_trw_obj = {
+       "trw", 19, 0,
+       NULL, &_wellfleet_obj
+},
+_mit_obj = {
+       "mit", 20, 0,
+       NULL, &_trw_obj
+},
+_eon_obj = {
+       "eon", 21, 0,
+       NULL, &_mit_obj
+},
+_spartacus_obj = {
+       "spartacus", 22, 0,
+       NULL, &_eon_obj
+},
+_excelan_obj = {
+       "excelan", 23, 0,
+       NULL, &_spartacus_obj
+},
+_spider_obj = {
+       "spider", 24, 0,
+       NULL, &_excelan_obj
+},
+_nsfnet_obj = {
+       "nsfnet", 25, 0,
+       NULL, &_spider_obj
+},
+_sytek_obj = {
+       "sytek", 26, 0,
+       NULL, &_nsfnet_obj
+},
+_intergraph_obj = {
+       "intergraph", 27, 0,
+       NULL, &_sytek_obj
+},
+_interlan_obj = {
+       "interlan", 28, 0,
+       NULL, &_intergraph_obj
+},
+_vitalink_obj = {
+       "vitalink", 29, 0,
+       NULL, &_interlan_obj
+},
+_ulana_obj = {
+       "ulana", 30, 0,
+       NULL, &_vitalink_obj
+},
+_nswc_obj = {
+       "nswc", 31, 0,
+       NULL, &_ulana_obj
+},
+_santacruzoperation_obj = {
+       "santacruzoperation", 32, 0,
+       NULL, &_nswc_obj
+},
+_xyplex_obj = {
+       "xyplex", 33, 0,
+       NULL, &_santacruzoperation_obj
+},
+_cray_obj = {
+       "cray", 34, 0,
+       NULL, &_xyplex_obj
+},
+_bellnorthernresearch_obj = {
+       "bellnorthernresearch", 35, 0,
+       NULL, &_cray_obj
+},
+_dec_obj = {
+       "dec", 36, 0,
+       NULL, &_bellnorthernresearch_obj
+},
+_touch_obj = {
+       "touch", 37, 0,
+       NULL, &_dec_obj
+},
+_networkresearchcorp_obj = {
+       "networkresearchcorp", 38, 0,
+       NULL, &_touch_obj
+},
+_baylor_obj = {
+       "baylor", 39, 0,
+       NULL, &_networkresearchcorp_obj
+},
+_nmfeccllnl_obj = {
+       "nmfeccllnl", 40, 0,
+       NULL, &_baylor_obj
+},
+_sri_obj = {
+       "sri", 41, 0,
+       NULL, &_nmfeccllnl_obj
+},
+_sun_obj = {
+       "sun", 42, 0,
+       NULL, &_sri_obj
+},
+_3com_obj = {
+       "3com", 43, 0,
+       NULL, &_sun_obj
+},
+_cmc_obj = {
+       "cmc", 44, 0,
+       NULL, &_3com_obj
+},
+_synoptics_obj = {
+       "synoptics", 45, 0,
+       NULL, &_cmc_obj
+},
+_cheyenne_obj = {
+       "cheyenne", 46, 0,
+       NULL, &_synoptics_obj
+},
+_prime_obj = {
+       "prime", 47, 0,
+       NULL, &_cheyenne_obj
+},
+_mcnc_obj = {
+       "mcnc", 48, 0,
+       NULL, &_prime_obj
+},
+_chipcom_obj = {
+       "chipcom", 49, 0,
+       NULL, &_mcnc_obj
+},
+_opticaldatasystems_obj = {
+       "opticaldatasystems", 50, 0,
+       NULL, &_chipcom_obj
+},
+_gated_obj = {
+       "gated", 51, 0,
+       NULL, &_opticaldatasystems_obj
+},
+_cabletron_obj = {
+       "cabletron", 52, 0,
+       NULL, &_gated_obj
+},
+_apollo_obj = {
+       "apollo", 53, 0,
+       NULL, &_cabletron_obj
+},
+_desktalksystems_obj = {
+       "desktalksystems", 54, 0,
+       NULL, &_apollo_obj
+},
+_ssds_obj = {
+       "ssds", 55, 0,
+       NULL, &_desktalksystems_obj
+},
+_castlerock_obj = {
+       "castlerock", 56, 0,
+       NULL, &_ssds_obj
+},
+_mips_obj = {
+       "mips", 57, 0,
+       NULL, &_castlerock_obj
+},
+_tgv_obj = {
+       "tgv", 58, 0,
+       NULL, &_mips_obj
+},
+_silicongraphics_obj = {
+       "silicongraphics", 59, 0,
+       NULL, &_tgv_obj
+},
+_ubc_obj = {
+       "ubc", 60, 0,
+       NULL, &_silicongraphics_obj
+},
+_merit_obj = {
+       "merit", 61, 0,
+       NULL, &_ubc_obj
+},
+_fibercom_obj = {
+       "fibercom", 62, 0,
+       NULL, &_merit_obj
+},
+_apple_obj = {
+       "apple", 63, 0,
+       NULL, &_fibercom_obj
+},
+_gandalf_obj = {
+       "gandalf", 64, 0,
+       NULL, &_apple_obj
+},
+_dartmouth_obj = {
+       "dartmouth", 65, 0,
+       NULL, &_gandalf_obj
+},
+_davidsystems_obj = {
+       "davidsystems", 66, 0,
+       NULL, &_dartmouth_obj
+},
+_reuter_obj = {
+       "reuter", 67, 0,
+       NULL, &_davidsystems_obj
+},
+_cornell_obj = {
+       "cornell", 68, 0,
+       NULL, &_reuter_obj
+},
+_tmac_obj = {
+       "tmac", 69, 0,
+       NULL, &_cornell_obj
+},
+_locus_obj = {
+       "locus", 70, 0,
+       NULL, &_tmac_obj
+},
+_nasa_obj = {
+       "nasa", 71, 0,
+       NULL, &_locus_obj
+},
+_retix_obj = {
+       "retix", 72, 0,
+       NULL, &_nasa_obj
+},
+_boeing_obj = {
+       "boeing", 73, 0,
+       NULL, &_retix_obj
+},
+_att_obj = {
+       "att", 74, 0,
+       NULL, &_boeing_obj
+},
+_ungermannbass_obj = {
+       "ungermannbass", 75, 0,
+       NULL, &_att_obj
+},
+_digitalanalysis_obj = {
+       "digitalanalysis", 76, 0,
+       NULL, &_ungermannbass_obj
+},
+_hplanman_obj = {
+       "hplanman", 77, 0,
+       NULL, &_digitalanalysis_obj
+},
+_netlabs_obj = {
+       "netlabs", 78, 0,
+       NULL, &_hplanman_obj
+},
+_icl_obj = {
+       "icl", 79, 0,
+       NULL, &_netlabs_obj
+},
+_auspex_obj = {
+       "auspex", 80, 0,
+       NULL, &_icl_obj
+},
+_lannet_obj = {
+       "lannet", 81, 0,
+       NULL, &_auspex_obj
+},
+_ncd_obj = {
+       "ncd", 82, 0,
+       NULL, &_lannet_obj
+},
+_raycom_obj = {
+       "raycom", 83, 0,
+       NULL, &_ncd_obj
+},
+_pirellifocom_obj = {
+       "pirellifocom", 84, 0,
+       NULL, &_raycom_obj
+},
+_datability_obj = {
+       "datability", 85, 0,
+       NULL, &_pirellifocom_obj
+},
+_networkappltech_obj = {
+       "networkappltech", 86, 0,
+       NULL, &_datability_obj
+},
+_link_obj = {
+       "link", 87, 0,
+       NULL, &_networkappltech_obj
+},
+_nyu_obj = {
+       "nyu", 88, 0,
+       NULL, &_link_obj
+},
+_rnd_obj = {
+       "rnd", 89, 0,
+       NULL, &_nyu_obj
+},
+_intercon_obj = {
+       "intercon", 90, 0,
+       NULL, &_rnd_obj
+},
+_learningtree_obj = {
+       "learningtree", 91, 0,
+       NULL, &_intercon_obj
+},
+_webstercomputer_obj = {
+       "webstercomputer", 92, 0,
+       NULL, &_learningtree_obj
+},
+_frontier_obj = {
+       "frontier", 93, 0,
+       NULL, &_webstercomputer_obj
+},
+_nokia_obj = {
+       "nokia", 94, 0,
+       NULL, &_frontier_obj
+},
+_allenbradley_obj = {
+       "allenbradley", 95, 0,
+       NULL, &_nokia_obj
+},
+_cern_obj = {
+       "cern", 96, 0,
+       NULL, &_allenbradley_obj
+},
+_sigma_obj = {
+       "sigma", 97, 0,
+       NULL, &_cern_obj
+},
+_emergingtech_obj = {
+       "emergingtech", 98, 0,
+       NULL, &_sigma_obj
+},
+_snmpresearch_obj = {
+       "snmpresearch", 99, 0,
+       NULL, &_emergingtech_obj
+},
+_ohiostate_obj = {
+       "ohiostate", 100, 0,
+       NULL, &_snmpresearch_obj
+},
+_ultra_obj = {
+       "ultra", 101, 0,
+       NULL, &_ohiostate_obj
+},
+_ccur_obj = {
+       "ccur", 136, 0,
+       NULL, &_ultra_obj
+},
+_enterprises_obj = {
+       "enterprises", 1, 0,
+       &_ccur_obj, NULL
+},
+_snmpInPkts_obj = {
+       "snmpInPkts", 1, 0,
+       NULL, NULL
+},
+_snmpOutPkts_obj = {
+       "snmpOutPkts", 2, 0,
+       NULL, &_snmpInPkts_obj
+},
+_snmpInBadVersions_obj = {
+       "snmpInBadVersions", 3, 0,
+       NULL, &_snmpOutPkts_obj
+},
+_snmpInBadCommunityNames_obj = {
+       "snmpInBadCommunityNames", 4, 0,
+       NULL, &_snmpInBadVersions_obj
+},
+_snmpInBadCommunityUses_obj = {
+       "snmpInBadCommunityUses", 5, 0,
+       NULL, &_snmpInBadCommunityNames_obj
+},
+_snmpInASNParseErrs_obj = {
+       "snmpInASNParseErrs", 6, 0,
+       NULL, &_snmpInBadCommunityUses_obj
+},
+_snmpInBadTypes_obj = {
+       "snmpInBadTypes", 7, 0,
+       NULL, &_snmpInASNParseErrs_obj
+},
+_snmpInTooBigs_obj = {
+       "snmpInTooBigs", 8, 0,
+       NULL, &_snmpInBadTypes_obj
+},
+_snmpInNoSuchNames_obj = {
+       "snmpInNoSuchNames", 9, 0,
+       NULL, &_snmpInTooBigs_obj
+},
+_snmpInBadValues_obj = {
+       "snmpInBadValues", 10, 0,
+       NULL, &_snmpInNoSuchNames_obj
+},
+_snmpInReadOnlys_obj = {
+       "snmpInReadOnlys", 11, 0,
+       NULL, &_snmpInBadValues_obj
+},
+_snmpInGenErrs_obj = {
+       "snmpInGenErrs", 12, 0,
+       NULL, &_snmpInReadOnlys_obj
+},
+_snmpInTotalReqVars_obj = {
+       "snmpInTotalReqVars", 13, 0,
+       NULL, &_snmpInGenErrs_obj
+},
+_snmpInTotalSetVars_obj = {
+       "snmpInTotalSetVars", 14, 0,
+       NULL, &_snmpInTotalReqVars_obj
+},
+_snmpInGetRequests_obj = {
+       "snmpInGetRequests", 15, 0,
+       NULL, &_snmpInTotalSetVars_obj
+},
+_snmpInGetNexts_obj = {
+       "snmpInGetNexts", 16, 0,
+       NULL, &_snmpInGetRequests_obj
+},
+_snmpInSetRequests_obj = {
+       "snmpInSetRequests", 17, 0,
+       NULL, &_snmpInGetNexts_obj
+},
+_snmpInGetResponses_obj = {
+       "snmpInGetResponses", 18, 0,
+       NULL, &_snmpInSetRequests_obj
+},
+_snmpInTraps_obj = {
+       "snmpInTraps", 19, 0,
+       NULL, &_snmpInGetResponses_obj
+},
+_snmpOutTooBigs_obj = {
+       "snmpOutTooBigs", 20, 0,
+       NULL, &_snmpInTraps_obj
+},
+_snmpOutNoSuchNames_obj = {
+       "snmpOutNoSuchNames", 21, 0,
+       NULL, &_snmpOutTooBigs_obj
+},
+_snmpOutBadValues_obj = {
+       "snmpOutBadValues", 22, 0,
+       NULL, &_snmpOutNoSuchNames_obj
+},
+_snmpOutReadOnlys_obj = {
+       "snmpOutReadOnlys", 23, 0,
+       NULL, &_snmpOutBadValues_obj
+},
+_snmpOutGenErrs_obj = {
+       "snmpOutGenErrs", 24, 0,
+       NULL, &_snmpOutReadOnlys_obj
+},
+_snmpOutGetRequests_obj = {
+       "snmpOutGetRequests", 25, 0,
+       NULL, &_snmpOutGenErrs_obj
+},
+_snmpOutGetNexts_obj = {
+       "snmpOutGetNexts", 26, 0,
+       NULL, &_snmpOutGetRequests_obj
+},
+_snmpOutSetRequests_obj = {
+       "snmpOutSetRequests", 27, 0,
+       NULL, &_snmpOutGetNexts_obj
+},
+_snmpOutGetResponses_obj = {
+       "snmpOutGetResponses", 28, 0,
+       NULL, &_snmpOutSetRequests_obj
+},
+_snmpOutTraps_obj = {
+       "snmpOutTraps", 29, 0,
+       NULL, &_snmpOutGetResponses_obj
+},
+_snmpEnableAuthTraps_obj = {
+       "snmpEnableAuthTraps", 30, 0,
+       NULL, &_snmpOutTraps_obj
+},
+_egpNeighState_obj = {
+       "egpNeighState", 1, 0,
+       NULL, NULL
+},
+_egpNeighAddr_obj = {
+       "egpNeighAddr", 2, 0,
+       NULL, &_egpNeighState_obj
+},
+_egpNeighAs_obj = {
+       "egpNeighAs", 3, 0,
+       NULL, &_egpNeighAddr_obj
+},
+_egpNeighInMsgs_obj = {
+       "egpNeighInMsgs", 4, 0,
+       NULL, &_egpNeighAs_obj
+},
+_egpNeighInErrs_obj = {
+       "egpNeighInErrs", 5, 0,
+       NULL, &_egpNeighInMsgs_obj
+},
+_egpNeighOutMsgs_obj = {
+       "egpNeighOutMsgs", 6, 0,
+       NULL, &_egpNeighInErrs_obj
+},
+_egpNeighOutErrs_obj = {
+       "egpNeighOutErrs", 7, 0,
+       NULL, &_egpNeighOutMsgs_obj
+},
+_egpNeighInErrMsgs_obj = {
+       "egpNeighInErrMsgs", 8, 0,
+       NULL, &_egpNeighOutErrs_obj
+},
+_egpNeighOutErrMsgs_obj = {
+       "egpNeighOutErrMsgs", 9, 0,
+       NULL, &_egpNeighInErrMsgs_obj
+},
+_egpNeighStateUps_obj = {
+       "egpNeighStateUps", 10, 0,
+       NULL, &_egpNeighOutErrMsgs_obj
+},
+_egpNeighStateDowns_obj = {
+       "egpNeighStateDowns", 11, 0,
+       NULL, &_egpNeighStateUps_obj
+},
+_egpNeighIntervalHello_obj = {
+       "egpNeighIntervalHello", 12, 0,
+       NULL, &_egpNeighStateDowns_obj
+},
+_egpNeighIntervalPoll_obj = {
+       "egpNeighIntervalPoll", 13, 0,
+       NULL, &_egpNeighIntervalHello_obj
+},
+_egpNeighMode_obj = {
+       "egpNeighMode", 14, 0,
+       NULL, &_egpNeighIntervalPoll_obj
+},
+_egpNeighEventTrigger_obj = {
+       "egpNeighEventTrigger", 15, 0,
+       NULL, &_egpNeighMode_obj
+},
+_egpNeighEntry_obj = {
+       "egpNeighEntry", 1, 0,
+       &_egpNeighEventTrigger_obj, NULL
+},
+_egpInMsgs_obj = {
+       "egpInMsgs", 1, 0,
+       NULL, NULL
+},
+_egpInErrors_obj = {
+       "egpInErrors", 2, 0,
+       NULL, &_egpInMsgs_obj
+},
+_egpOutMsgs_obj = {
+       "egpOutMsgs", 3, 0,
+       NULL, &_egpInErrors_obj
+},
+_egpOutErrors_obj = {
+       "egpOutErrors", 4, 0,
+       NULL, &_egpOutMsgs_obj
+},
+_egpNeighTable_obj = {
+       "egpNeighTable", 5, 0,
+       &_egpNeighEntry_obj, &_egpOutErrors_obj
+},
+_egpAs_obj = {
+       "egpAs", 6, 0,
+       NULL, &_egpNeighTable_obj
+},
+_udpLocalAddress_obj = {
+       "udpLocalAddress", 1, 0,
+       NULL, NULL
+},
+_udpLocalPort_obj = {
+       "udpLocalPort", 2, 0,
+       NULL, &_udpLocalAddress_obj
+},
+_udpEntry_obj = {
+       "udpEntry", 1, 0,
+       &_udpLocalPort_obj, NULL
+},
+_udpInDatagrams_obj = {
+       "udpInDatagrams", 1, 0,
+       NULL, NULL
+},
+_udpNoPorts_obj = {
+       "udpNoPorts", 2, 0,
+       NULL, &_udpInDatagrams_obj
+},
+_udpInErrors_obj = {
+       "udpInErrors", 3, 0,
+       NULL, &_udpNoPorts_obj
+},
+_udpOutDatagrams_obj = {
+       "udpOutDatagrams", 4, 0,
+       NULL, &_udpInErrors_obj
+},
+_udpTable_obj = {
+       "udpTable", 5, 0,
+       &_udpEntry_obj, &_udpOutDatagrams_obj
+},
+_tcpConnState_obj = {
+       "tcpConnState", 1, 0,
+       NULL, NULL
+},
+_tcpConnLocalAddress_obj = {
+       "tcpConnLocalAddress", 2, 0,
+       NULL, &_tcpConnState_obj
+},
+_tcpConnLocalPort_obj = {
+       "tcpConnLocalPort", 3, 0,
+       NULL, &_tcpConnLocalAddress_obj
+},
+_tcpConnRemAddress_obj = {
+       "tcpConnRemAddress", 4, 0,
+       NULL, &_tcpConnLocalPort_obj
+},
+_tcpConnRemPort_obj = {
+       "tcpConnRemPort", 5, 0,
+       NULL, &_tcpConnRemAddress_obj
+},
+_tcpConnEntry_obj = {
+       "tcpConnEntry", 1, 0,
+       &_tcpConnRemPort_obj, NULL
+},
+_tcpRtoAlgorithm_obj = {
+       "tcpRtoAlgorithm", 1, 0,
+       NULL, NULL
+},
+_tcpRtoMin_obj = {
+       "tcpRtoMin", 2, 0,
+       NULL, &_tcpRtoAlgorithm_obj
+},
+_tcpRtoMax_obj = {
+       "tcpRtoMax", 3, 0,
+       NULL, &_tcpRtoMin_obj
+},
+_tcpMaxConn_obj = {
+       "tcpMaxConn", 4, 0,
+       NULL, &_tcpRtoMax_obj
+},
+_tcpActiveOpens_obj = {
+       "tcpActiveOpens", 5, 0,
+       NULL, &_tcpMaxConn_obj
+},
+_tcpPassiveOpens_obj = {
+       "tcpPassiveOpens", 6, 0,
+       NULL, &_tcpActiveOpens_obj
+},
+_tcpAttemptFails_obj = {
+       "tcpAttemptFails", 7, 0,
+       NULL, &_tcpPassiveOpens_obj
+},
+_tcpEstabResets_obj = {
+       "tcpEstabResets", 8, 0,
+       NULL, &_tcpAttemptFails_obj
+},
+_tcpCurrEstab_obj = {
+       "tcpCurrEstab", 9, 0,
+       NULL, &_tcpEstabResets_obj
+},
+_tcpInSegs_obj = {
+       "tcpInSegs", 10, 0,
+       NULL, &_tcpCurrEstab_obj
+},
+_tcpOutSegs_obj = {
+       "tcpOutSegs", 11, 0,
+       NULL, &_tcpInSegs_obj
+},
+_tcpRetransSegs_obj = {
+       "tcpRetransSegs", 12, 0,
+       NULL, &_tcpOutSegs_obj
+},
+_tcpConnTable_obj = {
+       "tcpConnTable", 13, 0,
+       &_tcpConnEntry_obj, &_tcpRetransSegs_obj
+},
+_tcpInErrs_obj = {
+       "tcpInErrs", 14, 0,
+       NULL, &_tcpConnTable_obj
+},
+_tcpOutRsts_obj = {
+       "tcpOutRsts", 15, 0,
+       NULL, &_tcpInErrs_obj
+},
+_icmpInMsgs_obj = {
+       "icmpInMsgs", 1, 0,
+       NULL, NULL
+},
+_icmpInErrors_obj = {
+       "icmpInErrors", 2, 0,
+       NULL, &_icmpInMsgs_obj
+},
+_icmpInDestUnreachs_obj = {
+       "icmpInDestUnreachs", 3, 0,
+       NULL, &_icmpInErrors_obj
+},
+_icmpInTimeExcds_obj = {
+       "icmpInTimeExcds", 4, 0,
+       NULL, &_icmpInDestUnreachs_obj
+},
+_icmpInParmProbs_obj = {
+       "icmpInParmProbs", 5, 0,
+       NULL, &_icmpInTimeExcds_obj
+},
+_icmpInSrcQuenchs_obj = {
+       "icmpInSrcQuenchs", 6, 0,
+       NULL, &_icmpInParmProbs_obj
+},
+_icmpInRedirects_obj = {
+       "icmpInRedirects", 7, 0,
+       NULL, &_icmpInSrcQuenchs_obj
+},
+_icmpInEchos_obj = {
+       "icmpInEchos", 8, 0,
+       NULL, &_icmpInRedirects_obj
+},
+_icmpInEchoReps_obj = {
+       "icmpInEchoReps", 9, 0,
+       NULL, &_icmpInEchos_obj
+},
+_icmpInTimestamps_obj = {
+       "icmpInTimestamps", 10, 0,
+       NULL, &_icmpInEchoReps_obj
+},
+_icmpInTimestampReps_obj = {
+       "icmpInTimestampReps", 11, 0,
+       NULL, &_icmpInTimestamps_obj
+},
+_icmpInAddrMasks_obj = {
+       "icmpInAddrMasks", 12, 0,
+       NULL, &_icmpInTimestampReps_obj
+},
+_icmpInAddrMaskReps_obj = {
+       "icmpInAddrMaskReps", 13, 0,
+       NULL, &_icmpInAddrMasks_obj
+},
+_icmpOutMsgs_obj = {
+       "icmpOutMsgs", 14, 0,
+       NULL, &_icmpInAddrMaskReps_obj
+},
+_icmpOutErrors_obj = {
+       "icmpOutErrors", 15, 0,
+       NULL, &_icmpOutMsgs_obj
+},
+_icmpOutDestUnreachs_obj = {
+       "icmpOutDestUnreachs", 16, 0,
+       NULL, &_icmpOutErrors_obj
+},
+_icmpOutTimeExcds_obj = {
+       "icmpOutTimeExcds", 17, 0,
+       NULL, &_icmpOutDestUnreachs_obj
+},
+_icmpOutParmProbs_obj = {
+       "icmpOutParmProbs", 18, 0,
+       NULL, &_icmpOutTimeExcds_obj
+},
+_icmpOutSrcQuenchs_obj = {
+       "icmpOutSrcQuenchs", 19, 0,
+       NULL, &_icmpOutParmProbs_obj
+},
+_icmpOutRedirects_obj = {
+       "icmpOutRedirects", 20, 0,
+       NULL, &_icmpOutSrcQuenchs_obj
+},
+_icmpOutEchos_obj = {
+       "icmpOutEchos", 21, 0,
+       NULL, &_icmpOutRedirects_obj
+},
+_icmpOutEchoReps_obj = {
+       "icmpOutEchoReps", 22, 0,
+       NULL, &_icmpOutEchos_obj
+},
+_icmpOutTimestamps_obj = {
+       "icmpOutTimestamps", 23, 0,
+       NULL, &_icmpOutEchoReps_obj
+},
+_icmpOutTimestampReps_obj = {
+       "icmpOutTimestampReps", 24, 0,
+       NULL, &_icmpOutTimestamps_obj
+},
+_icmpOutAddrMasks_obj = {
+       "icmpOutAddrMasks", 25, 0,
+       NULL, &_icmpOutTimestampReps_obj
+},
+_icmpOutAddrMaskReps_obj = {
+       "icmpOutAddrMaskReps", 26, 0,
+       NULL, &_icmpOutAddrMasks_obj
+},
+_ipNetToMediaIfIndex_obj = {
+       "ipNetToMediaIfIndex", 1, 0,
+       NULL, NULL
+},
+_ipNetToMediaPhysAddress_obj = {
+       "ipNetToMediaPhysAddress", 2, 0,
+       NULL, &_ipNetToMediaIfIndex_obj
+},
+_ipNetToMediaNetAddress_obj = {
+       "ipNetToMediaNetAddress", 3, 0,
+       NULL, &_ipNetToMediaPhysAddress_obj
+},
+_ipNetToMediaType_obj = {
+       "ipNetToMediaType", 4, 0,
+       NULL, &_ipNetToMediaNetAddress_obj
+},
+_ipNetToMediaEntry_obj = {
+       "ipNetToMediaEntry", 1, 0,
+       &_ipNetToMediaType_obj, NULL
+},
+_ipRouteDest_obj = {
+       "ipRouteDest", 1, 0,
+       NULL, NULL
+},
+_ipRouteIfIndex_obj = {
+       "ipRouteIfIndex", 2, 0,
+       NULL, &_ipRouteDest_obj
+},
+_ipRouteMetric1_obj = {
+       "ipRouteMetric1", 3, 0,
+       NULL, &_ipRouteIfIndex_obj
+},
+_ipRouteMetric2_obj = {
+       "ipRouteMetric2", 4, 0,
+       NULL, &_ipRouteMetric1_obj
+},
+_ipRouteMetric3_obj = {
+       "ipRouteMetric3", 5, 0,
+       NULL, &_ipRouteMetric2_obj
+},
+_ipRouteMetric4_obj = {
+       "ipRouteMetric4", 6, 0,
+       NULL, &_ipRouteMetric3_obj
+},
+_ipRouteNextHop_obj = {
+       "ipRouteNextHop", 7, 0,
+       NULL, &_ipRouteMetric4_obj
+},
+_ipRouteType_obj = {
+       "ipRouteType", 8, 0,
+       NULL, &_ipRouteNextHop_obj
+},
+_ipRouteProto_obj = {
+       "ipRouteProto", 9, 0,
+       NULL, &_ipRouteType_obj
+},
+_ipRouteAge_obj = {
+       "ipRouteAge", 10, 0,
+       NULL, &_ipRouteProto_obj
+},
+_ipRouteMask_obj = {
+       "ipRouteMask", 11, 0,
+       NULL, &_ipRouteAge_obj
+},
+_ipRouteEntry_obj = {
+       "ipRouteEntry", 1, 0,
+       &_ipRouteMask_obj, NULL
+},
+_ipAdEntAddr_obj = {
+       "ipAdEntAddr", 1, 0,
+       NULL, NULL
+},
+_ipAdEntIfIndex_obj = {
+       "ipAdEntIfIndex", 2, 0,
+       NULL, &_ipAdEntAddr_obj
+},
+_ipAdEntNetMask_obj = {
+       "ipAdEntNetMask", 3, 0,
+       NULL, &_ipAdEntIfIndex_obj
+},
+_ipAdEntBcastAddr_obj = {
+       "ipAdEntBcastAddr", 4, 0,
+       NULL, &_ipAdEntNetMask_obj
+},
+_ipAdEntReasmMaxSize_obj = {
+       "ipAdEntReasmMaxSize", 5, 0,
+       NULL, &_ipAdEntBcastAddr_obj
+},
+_ipAddrEntry_obj = {
+       "ipAddrEntry", 1, 0,
+       &_ipAdEntReasmMaxSize_obj, NULL
+},
+_ipForwarding_obj = {
+       "ipForwarding", 1, 0,
+       NULL, NULL
+},
+_ipDefaultTTL_obj = {
+       "ipDefaultTTL", 2, 0,
+       NULL, &_ipForwarding_obj
+},
+_ipInReceives_obj = {
+       "ipInReceives", 3, 0,
+       NULL, &_ipDefaultTTL_obj
+},
+_ipInHdrErrors_obj = {
+       "ipInHdrErrors", 4, 0,
+       NULL, &_ipInReceives_obj
+},
+_ipInAddrErrors_obj = {
+       "ipInAddrErrors", 5, 0,
+       NULL, &_ipInHdrErrors_obj
+},
+_ipForwDatagrams_obj = {
+       "ipForwDatagrams", 6, 0,
+       NULL, &_ipInAddrErrors_obj
+},
+_ipInUnknownProtos_obj = {
+       "ipInUnknownProtos", 7, 0,
+       NULL, &_ipForwDatagrams_obj
+},
+_ipInDiscards_obj = {
+       "ipInDiscards", 8, 0,
+       NULL, &_ipInUnknownProtos_obj
+},
+_ipInDelivers_obj = {
+       "ipInDelivers", 9, 0,
+       NULL, &_ipInDiscards_obj
+},
+_ipOutRequests_obj = {
+       "ipOutRequests", 10, 0,
+       NULL, &_ipInDelivers_obj
+},
+_ipOutDiscards_obj = {
+       "ipOutDiscards", 11, 0,
+       NULL, &_ipOutRequests_obj
+},
+_ipOutNoRoutes_obj = {
+       "ipOutNoRoutes", 12, 0,
+       NULL, &_ipOutDiscards_obj
+},
+_ipReasmTimeout_obj = {
+       "ipReasmTimeout", 13, 0,
+       NULL, &_ipOutNoRoutes_obj
+},
+_ipReasmReqds_obj = {
+       "ipReasmReqds", 14, 0,
+       NULL, &_ipReasmTimeout_obj
+},
+_ipReasmOKs_obj = {
+       "ipReasmOKs", 15, 0,
+       NULL, &_ipReasmReqds_obj
+},
+_ipReasmFails_obj = {
+       "ipReasmFails", 16, 0,
+       NULL, &_ipReasmOKs_obj
+},
+_ipFragOKs_obj = {
+       "ipFragOKs", 17, 0,
+       NULL, &_ipReasmFails_obj
+},
+_ipFragFails_obj = {
+       "ipFragFails", 18, 0,
+       NULL, &_ipFragOKs_obj
+},
+_ipFragCreates_obj = {
+       "ipFragCreates", 19, 0,
+       NULL, &_ipFragFails_obj
+},
+_ipAddrTable_obj = {
+       "ipAddrTable", 20, 0,
+       &_ipAddrEntry_obj, &_ipFragCreates_obj
+},
+_ipRoutingTable_obj = {
+       "ipRoutingTable", 21, 0,
+       &_ipRouteEntry_obj, &_ipAddrTable_obj
+},
+_ipNetToMediaTable_obj = {
+       "ipNetToMediaTable", 22, 0,
+       &_ipNetToMediaEntry_obj, &_ipRoutingTable_obj
+},
+_atIfIndex_obj = {
+       "atIfIndex", 1, 0,
+       NULL, NULL
+},
+_atPhysAddress_obj = {
+       "atPhysAddress", 2, 0,
+       NULL, &_atIfIndex_obj
+},
+_atNetAddress_obj = {
+       "atNetAddress", 3, 0,
+       NULL, &_atPhysAddress_obj
+},
+_atEntry_obj = {
+       "atEntry", 1, 0,
+       &_atNetAddress_obj, NULL
+},
+_atTable_obj = {
+       "atTable", 1, 0,
+       &_atEntry_obj, NULL
+},
+_ifIndex_obj = {
+       "ifIndex", 1, 0,
+       NULL, NULL
+},
+_ifDescr_obj = {
+       "ifDescr", 2, 0,
+       NULL, &_ifIndex_obj
+},
+_ifType_obj = {
+       "ifType", 3, 0,
+       NULL, &_ifDescr_obj
+},
+_ifMtu_obj = {
+       "ifMtu", 4, 0,
+       NULL, &_ifType_obj
+},
+_ifSpeed_obj = {
+       "ifSpeed", 5, 0,
+       NULL, &_ifMtu_obj
+},
+_ifPhysAddress_obj = {
+       "ifPhysAddress", 6, 0,
+       NULL, &_ifSpeed_obj
+},
+_ifAdminStatus_obj = {
+       "ifAdminStatus", 7, 0,
+       NULL, &_ifPhysAddress_obj
+},
+_ifOperStatus_obj = {
+       "ifOperStatus", 8, 0,
+       NULL, &_ifAdminStatus_obj
+},
+_ifLastChange_obj = {
+       "ifLastChange", 9, 0,
+       NULL, &_ifOperStatus_obj
+},
+_ifInOctets_obj = {
+       "ifInOctets", 10, 0,
+       NULL, &_ifLastChange_obj
+},
+_ifInUcastPkts_obj = {
+       "ifInUcastPkts", 11, 0,
+       NULL, &_ifInOctets_obj
+},
+_ifInNUcastPkts_obj = {
+       "ifInNUcastPkts", 12, 0,
+       NULL, &_ifInUcastPkts_obj
+},
+_ifInDiscards_obj = {
+       "ifInDiscards", 13, 0,
+       NULL, &_ifInNUcastPkts_obj
+},
+_ifInErrors_obj = {
+       "ifInErrors", 14, 0,
+       NULL, &_ifInDiscards_obj
+},
+_ifInUnknownProtos_obj = {
+       "ifInUnknownProtos", 15, 0,
+       NULL, &_ifInErrors_obj
+},
+_ifOutOctets_obj = {
+       "ifOutOctets", 16, 0,
+       NULL, &_ifInUnknownProtos_obj
+},
+_ifOutUcastPkts_obj = {
+       "ifOutUcastPkts", 17, 0,
+       NULL, &_ifOutOctets_obj
+},
+_ifOutNUcastPkts_obj = {
+       "ifOutNUcastPkts", 18, 0,
+       NULL, &_ifOutUcastPkts_obj
+},
+_ifOutDiscards_obj = {
+       "ifOutDiscards", 19, 0,
+       NULL, &_ifOutNUcastPkts_obj
+},
+_ifOutErrors_obj = {
+       "ifOutErrors", 20, 0,
+       NULL, &_ifOutDiscards_obj
+},
+_ifOutQLen_obj = {
+       "ifOutQLen", 21, 0,
+       NULL, &_ifOutErrors_obj
+},
+_ifSpecific_obj = {
+       "ifSpecific", 22, 0,
+       NULL, &_ifOutQLen_obj
+},
+_ifEntry_obj = {
+       "ifEntry", 1, 0,
+       &_ifSpecific_obj, NULL
+},
+_ifNumber_obj = {
+       "ifNumber", 1, 0,
+       NULL, NULL
+},
+_ifTable_obj = {
+       "ifTable", 2, 0,
+       &_ifEntry_obj, &_ifNumber_obj
+},
+_sysDescr_obj = {
+       "sysDescr", 1, 0,
+       NULL, NULL
+},
+_sysObjectID_obj = {
+       "sysObjectID", 2, 0,
+       NULL, &_sysDescr_obj
+},
+_sysUpTime_obj = {
+       "sysUpTime", 3, 0,
+       NULL, &_sysObjectID_obj
+},
+_sysContact_obj = {
+       "sysContact", 4, 0,
+       NULL, &_sysUpTime_obj
+},
+_sysName_obj = {
+       "sysName", 5, 0,
+       NULL, &_sysContact_obj
+},
+_sysLocation_obj = {
+       "sysLocation", 6, 0,
+       NULL, &_sysName_obj
+},
+_sysServices_obj = {
+       "sysServices", 7, 0,
+       NULL, &_sysLocation_obj
+},
+_system_obj = {
+       "system", 1, 0,
+       &_sysServices_obj, NULL
+},
+_interfaces_obj = {
+       "interfaces", 2, 0,
+       &_ifTable_obj, &_system_obj
+},
+_at_obj = {
+       "at", 3, 0,
+       &_atTable_obj, &_interfaces_obj
+},
+_ip_obj = {
+       "ip", 4, 0,
+       &_ipNetToMediaTable_obj, &_at_obj
+},
+_icmp_obj = {
+       "icmp", 5, 0,
+       &_icmpOutAddrMaskReps_obj, &_ip_obj
+},
+_tcp_obj = {
+       "tcp", 6, 0,
+       &_tcpOutRsts_obj, &_icmp_obj
+},
+_udp_obj = {
+       "udp", 7, 0,
+       &_udpTable_obj, &_tcp_obj
+},
+_egp_obj = {
+       "egp", 8, 0,
+       &_egpAs_obj, &_udp_obj
+},
+_transmission_obj = {
+       "transmission", 10, 0,
+       NULL, &_egp_obj
+},
+_snmp_obj = {
+       "snmp", 11, 0,
+       &_snmpEnableAuthTraps_obj, &_transmission_obj
+},
+_mib_obj = {
+       "mib", 1, 0,
+       &_snmp_obj, NULL
+},
+_directory_obj = {
+       "directory", 1, 0,
+       NULL, NULL
+},
+_mgmt_obj = {
+       "mgmt", 2, 0,
+       &_mib_obj, &_directory_obj
+},
+_experimental_obj = {
+       "experimental", 3, 0,
+       NULL, &_mgmt_obj
+},
+_private_obj = {
+       "private", 4, 0,
+       &_enterprises_obj, &_experimental_obj
+},
+_internet_obj = {
+       "internet", 1, 0,
+       &_private_obj, NULL
+},
+_dod_obj = {
+       "dod", 6, 0,
+       &_internet_obj, NULL
+},
+_org_obj = {
+       "org", 3, 0,
+       &_dod_obj, NULL
+},
+_iso_obj = {
+       "iso", 1, 0,
+       &_org_obj, NULL
+},
+*mibroot = &_iso_obj;
diff --git a/usr/src/contrib/tcpdump/tcpdump/nametoaddr.c b/usr/src/contrib/tcpdump/tcpdump/nametoaddr.c
new file mode 100644 (file)
index 0000000..6f2330f
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Name to id translation routines used by the scanner.
+ * These functions are not time critical.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: nametoaddr.c,v 1.9 91/02/04 16:56:46 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#ifdef ultrix
+#include <sys/time.h>
+#include <rpc/types.h>
+#include <nfs/nfs.h>
+#endif
+
+#include "interface.h"
+#include "etherent.h"
+#include "nametoaddr.h"
+
+/*
+ *  Convert host name to internet address.
+ *  Return 0 upon failure.
+ */
+u_long **
+s_nametoaddr(name)
+       char *name;
+{
+#ifndef h_addr
+       static u_long *hlist[2];
+#endif
+       u_long **p;
+       struct hostent *hp;
+
+       if (hp = gethostbyname(name)) {
+#ifndef h_addr
+               hlist[0] = (u_long *)hp->h_addr;
+               NTOHL(hp->h_addr);
+               return hlist;
+#else
+               for (p = (u_long **)hp->h_addr_list; *p; ++p)
+                       NTOHL(**p);
+               return (u_long **)hp->h_addr_list;
+#endif
+       }
+       else
+               return 0;
+}
+
+/*
+ *  Convert net name to internet address.
+ *  Return 0 upon failure.
+ */
+u_long
+s_nametonetaddr(name)
+       char *name;
+{
+       struct netent *np;
+
+       if (np = getnetbyname(name))
+               return np->n_net;
+       else
+               return 0;
+}
+
+/*
+ * Convert a port name to its port and protocol numbers.
+ * We assume only TCP or UDP.
+ * Return 0 upon failure.
+ */
+s_nametoport(name, port, proto)
+       char *name;
+       int *port;
+       int *proto;
+{
+       struct servent *sp;
+       char *other;
+
+       sp = getservbyname(name, (char *)0);
+       if (sp != 0) {
+               NTOHS(sp->s_port);
+               *port = sp->s_port;
+               *proto = s_nametoproto(sp->s_proto);
+               /*
+                * We need to check /etc/services for ambiguous entries. 
+                * If we find the ambiguous entry, and it has the
+                * same port number, change the proto to PROTO_UNDEF
+                * so both TCP and UDP will be checked.
+                */
+               if (*proto == IPPROTO_TCP)
+                       other = "udp";
+               else
+                       other = "tcp";
+
+               sp = getservbyname(name, other);
+               if (sp != 0) {
+                       NTOHS(sp->s_port);
+                       if (*port != sp->s_port)
+                               /* Can't handle ambigous names that refer
+                                  to different port numbers. */
+                               warning("ambiguous port %s in /etc/services",
+                                       name);
+                       *proto = PROTO_UNDEF;
+               }
+               return 1;
+       }
+#ifdef ultrix
+       /* Special hack in case NFS isn't in /etc/services */
+       if (strcmp(name, "nfs") == 0) {
+               *port = NFS_PORT;
+               *proto = PROTO_UNDEF;
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+int
+s_nametoproto(str)
+       char *str;
+{
+       struct protoent *p;
+
+       p = getprotobyname(str);
+       if (p != 0)
+               return p->p_proto;
+       else
+               return PROTO_UNDEF;
+}
+
+#include "etherproto.h"
+
+int
+s_nametoeproto(s)
+       char *s;
+{
+       struct eproto *p = eproto_db;
+
+       while (p->s != 0) {
+               if (strcmp(p->s, s) == 0)
+                       return p->p;
+               p += 1;
+       }
+       return PROTO_UNDEF;
+}
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+       if (isdigit(c))
+               return c - '0';
+       else if (islower(c))
+               return c - 'a' + 10;
+       else
+               return c - 'A' + 10;
+}
+
+u_long
+atoin(s)
+       char *s;
+{
+       u_long addr = 0;
+       u_int n;
+
+       while (1) {
+               n = 0;
+               while (*s && *s != '.') 
+                       n = n * 10 + *s++ - '0';
+               addr <<= 8;
+               addr |= n & 0xff;
+               if (*s == '\0')
+                       return addr;
+               ++s;
+       }
+       /* NOTREACHED */
+}
+       
+
+/*
+ * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new 
+ * ethernet address.  Assumes 's' is well formed.
+ */
+u_char *
+ETHER_aton(s)
+       char *s;
+{
+       register u_char *ep, *e;
+       register u_int d;
+
+       e = ep = (u_char *)malloc(6);
+       
+       while (*s) {
+               if (*s == ':')
+                       s += 1;
+               d = xdtoi(*s++);
+               if (isxdigit(*s)) {
+                       d <<= 4;
+                       d |= xdtoi(*s++);
+               }
+               *ep++ = d;
+       }
+
+       return e;
+}
+
+#ifndef ETHER_SERVICE
+u_char *
+ETHER_hostton(name)
+       char *name;
+{
+       struct etherent *ep;
+       FILE *fp;
+       u_char *ap;
+
+       fp = fopen(ETHERS_FILE, "r");
+       if (fp != 0) {
+               while (ep = next_etherent(fp)) {
+                       if (strcmp(ep->name, name) == 0) {
+                               ap = (u_char *)malloc(6);
+                               bcopy(ep->addr, ap, 6);
+                               return ap;
+                       }
+               }
+       }
+       return (u_char *)0;
+}
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/nametoaddr.h b/usr/src/contrib/tcpdump/tcpdump/nametoaddr.h
new file mode 100644 (file)
index 0000000..23da3f2
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: nametoaddr.h,v 1.6 90/09/24 12:50:41 mccanne Exp $ (LBL)
+ *
+ * Address to name translation routines.
+ */
+
+extern u_long **s_nametoaddr();
+extern u_long s_nametonetaddr();
+
+extern int s_nametoport();
+extern int s_nametoproto();
+extern int s_nametoeproto();
+
+extern u_char *ETHER_hostton();
+extern u_char *ETHER_aton();
+
+/*
+ * If a protocol is unknown, PROTO_UNDEF is returned.
+ * Also, s_nametoport() returns the protocol along with the port number.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF            -1
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/ntp.h b/usr/src/contrib/tcpdump/tcpdump/ntp.h
new file mode 100644 (file)
index 0000000..493686d
--- /dev/null
@@ -0,0 +1,117 @@
+/* $Header: ntp.h,v 1.1 90/08/07 11:08:27 mogul Exp $ */
+
+/*
+ * Based on ntp.h from the U of MD implementation
+ *     This file is based on Version 2 of the NTP spec (RFC1119).
+ */
+
+/*
+ *  Definitions for the masses
+ */
+#define        JAN_1970        2208988800      /* 1970 - 1900 in seconds */
+
+/*
+ * Structure definitions for NTP fixed point values
+ *
+ *    0                          1                   2                   3
+ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                        Integer Part                          |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                        Fraction Part                         |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *    0                          1                   2                   3
+ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |           Integer Part       |     Fraction Part             |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct l_fixedpt {
+       u_long int_part;
+       u_long fraction;
+};
+
+struct s_fixedpt {
+       u_short int_part;
+       u_short fraction;
+};
+
+/*  =================  Table 3.3. Packet Variables   ================= */
+/*
+ *    0                          1                   2                   3
+ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |LI | VN  | Mode|   Stratum    |      Poll     |   Precision   |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                    Synchronizing Distance                    |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                   Synchronizing Dispersion                   |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                 Reference Clock Identifier                   |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                                                              |
+ *   |                Reference Timestamp (64 bits)                 |
+ *   |                                                              |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                                                              |
+ *   |                Originate Timestamp (64 bits)                 |
+ *   |                                                              |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                                                              |
+ *   |                 Receive Timestamp (64 bits)                  |
+ *   |                                                              |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *   |                                                              |
+ *   |                 Transmit Timestamp (64 bits)                 |
+ *   |                                                              |
+ *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct ntpdata {
+       u_char status;          /* status of local clock and leap info */
+       u_char stratum;         /* Stratum level */
+       u_char ppoll;           /* poll value */
+       int precision:8;
+       struct s_fixedpt distance;
+       struct s_fixedpt dispersion;
+       u_long refid;
+       struct l_fixedpt reftime;
+       struct l_fixedpt org;
+       struct l_fixedpt rec;
+       struct l_fixedpt xmt;
+};
+/*
+ *     Leap Second Codes (high order two bits)
+ */
+#define        NO_WARNING      0x00    /* no warning */
+#define        PLUS_SEC        0x40    /* add a second (61 seconds) */
+#define        MINUS_SEC       0x80    /* minus a second (59 seconds) */
+#define        ALARM           0xc0    /* alarm condition (clock unsynchronized) */
+
+/*
+ *     Clock Status Bits that Encode Version
+ */
+#define        NTPVERSION_1    0x08
+#define        VERSIONMASK     0x38
+#define LEAPMASK       0xc0
+#define        MODEMASK        0x07
+
+/*
+ *     Code values
+ */
+#define        MODE_UNSPEC     0       /* unspecified */
+#define        MODE_SYM_ACT    1       /* symmetric active */
+#define        MODE_SYM_PAS    2       /* symmetric passive */
+#define        MODE_CLIENT     3       /* client */
+#define        MODE_SERVER     4       /* server */
+#define        MODE_BROADCAST  5       /* broadcast */
+#define        MODE_RES1       6       /* reserved */
+#define        MODE_RES2       7       /* reserved */
+
+/*
+ *     Stratum Definitions
+ */
+#define        UNSPECIFIED     0
+#define        PRIM_REF        1       /* radio clock */
+#define        INFO_QUERY      62      /* **** THIS implementation dependent **** */
+#define        INFO_REPLY      63      /* **** THIS implementation dependent **** */
diff --git a/usr/src/contrib/tcpdump/tcpdump/optimize.c b/usr/src/contrib/tcpdump/tcpdump/optimize.c
new file mode 100644 (file)
index 0000000..5064011
--- /dev/null
@@ -0,0 +1,1871 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Optimization module for tcpdump intermediate representation.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: optimize.c,v 1.35 91/07/18 09:27:55 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "gencode.h"
+
+#define A_ATOM BPF_MEMWORDS
+#define X_ATOM (BPF_MEMWORDS+1)
+
+#define NOP -1
+
+/*
+ * This define is used to represent *both* the accumulator and
+ * x register in use-def computations.
+ * Currently, the use-def code assumes only one definition per instruction.
+ */
+#define AX_ATOM N_ATOMS
+
+/*
+ * A flag to indicate that further optimization is needed.
+ * Iterative passes are continued until a given pass yields no 
+ * branch movement.
+ */
+static int done;
+
+/*
+ * A block is marked if only if its mark equals the current mark.
+ * Rather than traverse the code array, marking each item, 'cur_mark' is
+ * incremented.  This automatically makes each element unmarked.
+ */
+static int cur_mark;
+#define isMarked(p) ((p)->mark == cur_mark)
+#define unMarkAll() cur_mark += 1
+#define Mark(p) ((p)->mark = cur_mark)
+
+static void opt_init();
+static void opt_cleanup();
+
+static void make_marks();
+static void mark_code();
+
+static void intern_blocks();
+
+static int eq_slist();
+
+static int n_blocks;
+struct block **blocks;
+static int n_edges;
+struct edge **edges;
+
+/*
+ * A bit vector set representation of the dominators.  
+ * We round up the set size to the next power of two.  
+ */
+static int nodewords;
+static int edgewords;
+struct block **levels;
+u_long *space;
+#define BITS_PER_WORD (8*sizeof(u_long))
+/*
+ * True if a is in uset {p}
+ */
+#define SET_MEMBER(p, a) \
+((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
+
+/*
+ * Add 'a' to uset p.
+ */
+#define SET_INSERT(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * Delete 'a' from uset p.
+ */
+#define SET_DELETE(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * a := a intersect b
+ */
+#define SET_INTERSECT(a, b, n)\
+{\
+       register u_long *_x = a, *_y = b;\
+       register int _n = n;\
+       while (--_n >= 0) *_x++ &= *_y++;\
+}
+
+/*
+ * a := a - b
+ */
+#define SET_SUBTRACT(a, b, n)\
+{\
+       register u_long *_x = a, *_y = b;\
+       register int _n = n;\
+       while (--_n >= 0) *_x++ &=~ *_y++;\
+}
+
+/*
+ * a := a union b
+ */
+#define SET_UNION(a, b, n)\
+{\
+       register u_long *_x = a, *_y = b;\
+       register int _n = n;\
+       while (--_n >= 0) *_x++ |= *_y++;\
+}
+
+static uset all_dom_sets;
+static uset all_closure_sets;
+static uset all_edge_sets;
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+static void
+find_levels_r(b)
+       struct block *b;
+{
+       int level;
+
+       if (isMarked(b))
+               return;
+
+       Mark(b);
+       b->link = 0;
+
+       if (JT(b)) {
+               find_levels_r(JT(b));
+               find_levels_r(JF(b));
+               level = MAX(JT(b)->level, JF(b)->level) + 1;
+       } else
+               level = 0;
+       b->level = level;
+       b->link = levels[level];
+       levels[level] = b;
+}
+
+/*
+ * Level graph.  The levels go from 0 at the leaves to 
+ * N_LEVELS at the root.  The levels[] array points to the
+ * first node of the level list, whose elements are linked
+ * with the 'link' field of the struct block.
+ */
+static void
+find_levels(root)
+       struct block *root;
+{
+       bzero((char *)levels, n_blocks * sizeof(*levels));
+       unMarkAll();
+       find_levels_r(root);
+}
+
+/* 
+ * Find dominator relationships.
+ * Assumes graph has been leveled.
+ */
+static void
+find_dom(root)
+       struct block *root;
+{
+       int i;
+       struct block *b;
+       u_long *x;
+
+       /*
+        * Initialize sets to contain all nodes.
+        */
+       x = all_dom_sets;
+       i = n_blocks * nodewords;
+       while (--i >= 0)
+               *x++ = ~0;
+       /* Root starts off empty. */
+       for (i = nodewords; --i >= 0;)
+               root->dom[i] = 0;
+       
+       /* root->level is the highest level no found. */
+       for (i = root->level; i >= 0; --i) {
+               for (b = levels[i]; b; b = b->link) {
+                       SET_INSERT(b->dom, b->id);
+                       if (JT(b) == 0)
+                               continue;
+                       SET_INTERSECT(JT(b)->dom, b->dom, nodewords);
+                       SET_INTERSECT(JF(b)->dom, b->dom, nodewords);
+               }
+       }
+}
+
+static void
+propedom(ep)
+       struct edge *ep;
+{
+       SET_INSERT(ep->edom, ep->id);
+       if (ep->succ) {
+               SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords);
+               SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords);
+       }
+}
+
+/* 
+ * Compute edge dominators.
+ * Assumes graph has been leveled and predecessors estabished.
+ */
+static void
+find_edom(root)
+       struct block *root;
+{
+       int i;
+       uset x;
+       struct block *b;
+
+       x = all_edge_sets;
+       for (i = n_edges * edgewords; --i >= 0; )
+               x[i] = ~0;
+
+       /* root->level is the highest level no found. */
+       bzero(root->et.edom, edgewords * sizeof(*(uset)0));
+       bzero(root->ef.edom, edgewords * sizeof(*(uset)0));
+       for (i = root->level; i >= 0; --i) {
+               for (b = levels[i]; b != 0; b = b->link) {
+                       propedom(&b->et);
+                       propedom(&b->ef);
+               }
+       }
+}
+
+/* 
+ * Find the backwards transitive closure of the flow graph.  These sets
+ * are backwards in the sense that we find the set of nodes that reach
+ * a given node, not the set of nodes that can be reached by a node.
+ *
+ * Assumes graph has been leveled.
+ */
+static void
+find_closure(root)
+       struct block *root;
+{
+       int i;
+       struct block *b;
+
+       /*
+        * Initialize sets to contain no nodes.
+        */
+       bzero((char *)all_closure_sets, 
+             n_blocks * nodewords * sizeof(*all_closure_sets));
+       
+       /* root->level is the highest level no found. */
+       for (i = root->level; i >= 0; --i) {
+               for (b = levels[i]; b; b = b->link) {
+                       SET_INSERT(b->closure, b->id);
+                       if (JT(b) == 0)
+                               continue;
+                       SET_UNION(JT(b)->closure, b->closure, nodewords);
+                       SET_UNION(JF(b)->closure, b->closure, nodewords);
+               }
+       }
+}
+
+/* 
+ * Return the register number that is used by s.  If A and X are both
+ * used, return AX_ATOM.  If no register is used, return -1.
+ * 
+ * The implementation should probably change to an array access.
+ */
+static int
+atomuse(s)
+       struct stmt *s;
+{
+       register int c = s->code;
+
+       if (c == NOP)
+               return -1;
+
+       switch (BPF_CLASS(c)) {
+
+       case BPF_RET:
+               return (BPF_RVAL(c) == BPF_A) ? A_ATOM : 
+                       (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
+
+       case BPF_LD:
+       case BPF_LDX:
+               return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
+                       (BPF_MODE(c) == BPF_MEM) ? s->k : -1;
+
+       case BPF_ST:
+               return A_ATOM;
+
+       case BPF_STX:
+               return X_ATOM;
+
+       case BPF_JMP:
+       case BPF_ALU:
+               if (BPF_SRC(c) == BPF_X)
+                       return AX_ATOM;
+               return A_ATOM;
+
+       case BPF_MISC:
+               return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
+       }
+       abort();
+       /* NOTREACHED */
+}
+
+/* 
+ * Return the register number that is defined by 's'.  We assume that
+ * a single stmt cannot define more than one register.  If no register
+ * is defined, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomdef(s)
+       struct stmt *s;
+{
+       if (s->code == NOP)
+               return -1;
+
+       switch (BPF_CLASS(s->code)) {
+
+       case BPF_LD:
+       case BPF_ALU:
+               return A_ATOM;
+
+       case BPF_LDX:
+               return X_ATOM;
+
+       case BPF_ST:
+       case BPF_STX:
+               return s->k;
+
+       case BPF_MISC:
+               return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
+       }
+       return -1;
+}
+
+static void
+compute_local_ud(b)
+       struct block *b;
+{
+       struct slist *s;
+       atomset def = 0, use = 0, kill = 0;
+       int atom;
+
+       for (s = b->stmts; s; s = s->next) {
+               if (s->s.code == NOP)
+                       continue;
+               atom = atomuse(&s->s);
+               if (atom >= 0) {
+                       if (atom == AX_ATOM) {
+                               if (!ATOMELEM(def, X_ATOM))
+                                       use |= ATOMMASK(X_ATOM);
+                               if (!ATOMELEM(def, A_ATOM))
+                                       use |= ATOMMASK(A_ATOM);
+                       }
+                       else if (atom < N_ATOMS) {
+                               if (!ATOMELEM(def, atom))
+                                       use |= ATOMMASK(atom);
+                       }
+                       else
+                               abort();
+               }
+               atom = atomdef(&s->s);
+               if (atom >= 0) {
+                       if (!ATOMELEM(atom, use))
+                               kill |= ATOMMASK(atom);
+                       def |= ATOMMASK(atom);
+               }
+       }
+       if (!ATOMELEM(def, A_ATOM) && BPF_CLASS(b->s.code) == BPF_JMP)
+               use |= ATOMMASK(A_ATOM);
+               
+       b->def = def;
+       b->kill = kill;
+       b->in_use = use;
+}
+
+/*
+ * Assume graph is already leveled.
+ */
+static void
+find_ud(root)
+       struct block *root;
+{
+       int i, maxlevel;
+       struct block *p;
+
+       /*
+        * root->level is the highest level no found;
+        * count down from there.
+        */
+       maxlevel = root->level;
+       for (i = maxlevel; i >= 0; --i)
+               for (p = levels[i]; p; p = p->link) {
+                       compute_local_ud(p);
+                       p->out_use = 0;
+               }
+
+       for (i = 1; i <= maxlevel; ++i) {
+               for (p = levels[i]; p; p = p->link) {
+                       p->out_use |= JT(p)->in_use | JF(p)->in_use;
+                       p->in_use |= p->out_use &~ p->kill;
+               }
+       }
+}
+
+/* 
+ * These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme.  Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined.
+ */
+struct valnode {
+       int code;
+       long v0, v1;
+       long val;
+       struct valnode *next;
+};
+       
+#define MODULUS 213
+static struct valnode *hashtbl[MODULUS];
+static int curval;
+static int maxval;
+
+/* Integer constants mapped with the load immediate opcode. */
+#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)
+
+struct vmapinfo {
+       int is_const;
+       long const_val;
+};
+
+struct vmapinfo *vmap;
+struct valnode *vnode_base;
+struct valnode *next_vnode;
+
+static void
+init_val()
+{
+       curval = 0;
+       next_vnode = vnode_base;
+       bzero((char *)vmap, maxval * sizeof(*vmap));
+       bzero((char *)hashtbl, sizeof hashtbl);
+}
+
+/* Because we really don't have an IR, this stuff is a little messy. */
+static long
+F(code, v0, v1)
+       int code;
+       long v0, v1;
+{
+       u_int hash;
+       int val;
+       struct valnode *p;
+
+       hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+       hash %= MODULUS;
+
+       for (p = hashtbl[hash]; p; p = p->next)
+               if (p->code == code && p->v0 == v0 && p->v1 == v1)
+                       return p->val;
+
+       val = ++curval;
+       if (BPF_MODE(code) == BPF_IMM && 
+           (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
+               vmap[val].const_val = v0;
+               vmap[val].is_const = 1;
+       }
+       p = next_vnode++;
+       p->val = val;
+       p->code = code;
+       p->v0 = v0;
+       p->v1 = v1;
+       p->next = hashtbl[hash];
+       hashtbl[hash] = p;
+
+       return val;
+}
+
+static inline void
+vstore(s, valp, newval, alter)
+       struct stmt *s;
+       long *valp;
+       long newval;
+       int alter;
+{
+       if (alter && *valp == newval)
+               s->code = NOP;
+       else
+               *valp = newval;
+}
+
+static void
+fold_op(s, v0, v1)
+       struct stmt *s;
+       long v0, v1;
+{
+       long a, b;
+
+       a = vmap[v0].const_val;
+       b = vmap[v1].const_val;
+
+       switch (BPF_OP(s->code)) {
+       case BPF_ADD:
+               a += b;
+               break;
+
+       case BPF_SUB:
+               a -= b;
+               break;
+
+       case BPF_MUL:
+               a *= b;
+               break;
+
+       case BPF_DIV:
+               if (b == 0)
+                       error("division by zero");
+               a /= b;
+               break;
+
+       case BPF_AND:
+               a &= b;
+               break;
+
+       case BPF_OR:
+               a |= b;
+               break;
+
+       case BPF_LSH:
+               a <<= b;
+               break;
+
+       case BPF_RSH:
+               a >>= b;
+               break;
+
+       case BPF_NEG:
+               a = -a;
+               break;
+
+       default:
+               abort();
+       }
+       s->k = a;
+       s->code = BPF_LD|BPF_IMM;
+       done = 0;
+}
+
+static inline struct slist *
+this_op(s)
+       struct slist *s;
+{
+       while (s != 0 && s->s.code == NOP)
+               s = s->next;
+       return s;
+}
+
+static void
+opt_not(b)
+       struct block *b;
+{
+       struct block *tmp = JT(b);
+
+       JT(b) = JF(b);
+       JF(b) = tmp;
+}
+
+static void
+opt_peep(b)
+       struct block *b;
+{
+       struct slist *s;
+       struct slist *next, *last;
+       int val;
+       long v;
+
+       s = b->stmts;
+       if (s == 0)
+               return;
+
+       last = s;
+       while (1) {
+               s = this_op(s);
+               if (s == 0)
+                       break;
+               next = this_op(s->next);
+               if (next == 0)
+                       break;
+               last = next;
+
+               /*
+                * st  M[k]     -->     st  M[k]
+                * ldx M[k]             tax
+                */
+               if (s->s.code == BPF_ST &&
+                   next->s.code == (BPF_LDX|BPF_MEM) &&
+                   s->s.k == next->s.k) {
+                       done = 0;
+                       next->s.code = BPF_MISC|BPF_TAX;
+               }
+               /*
+                * ld  #k       -->     ldx  #k
+                * tax                  txa
+                */
+               if (s->s.code == (BPF_LD|BPF_IMM) &&
+                   next->s.code == (BPF_MISC|BPF_TAX)) {
+                       s->s.code = BPF_LDX|BPF_IMM;
+                       next->s.code = BPF_MISC|BPF_TXA;
+                       done = 0;
+               }
+               /*
+                * This is an ugly special case, but it happens
+                * when you say tcp[k] or udp[k] where k is a constant.
+                */
+               if (s->s.code == (BPF_LD|BPF_IMM)) {
+                       struct slist *add, *tax, *ild;
+
+                       /*
+                        * Check that X isn't used on exit from this
+                        * block (which the optimizer might cause).
+                        * We know the code generator won't generate
+                        * any local dependencies.
+                        */
+                       if (ATOMELEM(b->out_use, X_ATOM))
+                               break;
+
+                       if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+                               add = next;
+                       else
+                               add = this_op(next->next);
+                       if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
+                               break;
+
+                       tax = this_op(add->next);
+                       if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
+                               break;
+
+                       ild = this_op(tax->next);
+                       if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || 
+                           BPF_MODE(ild->s.code) != BPF_IND)
+                               break;
+                       /* 
+                        * XXX We need to check that X is not
+                        * subsequently used.  We know we can eliminate the
+                        * accumulator modifications since it is defined
+                        * by the last stmt of this sequence.
+                        *
+                        * We want to turn this sequence:
+                        *
+                        * (004) ldi     #0x2           {s}
+                        * (005) ldxms   [14]           {next}  -- optional
+                        * (006) addx                   {add}
+                        * (007) tax                    {tax}
+                        * (008) ild     [x+0]          {ild}
+                        *
+                        * into this sequence:
+                        *
+                        * (004) nop
+                        * (005) ldxms   [14]
+                        * (006) nop
+                        * (007) nop
+                        * (008) ild     [x+2]
+                        *
+                        */
+                       ild->s.k += s->s.k;
+                       s->s.code = NOP;
+                       add->s.code = NOP;
+                       tax->s.code = NOP;
+                       done = 0;
+               }
+               s = next;
+       }
+       /*
+        * If we have a subtract to do a comparsion, and the X register
+        * is a known constant, we can merge this value into the 
+        * comparison.
+        */
+       if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X) &&
+           !ATOMELEM(b->out_use, A_ATOM)) {
+               val = b->val[X_ATOM];
+               if (vmap[val].is_const) {
+                       b->s.k += vmap[val].const_val;
+                       last->s.code = NOP;
+                       done = 0;
+               } else if (b->s.k == 0) {
+                       /*
+                        * sub x  ->    nop
+                        * j  #0        j  x
+                        */
+                       last->s.code = NOP;
+                       b->s.code = BPF_CLASS(b->s.code) | BPF_OP(b->s.code) |
+                               BPF_X;
+                       done = 0;
+               }
+       }
+       /*
+        * Likewise, a constant subtract can be simplified.
+        */
+       else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K) &&
+                !ATOMELEM(b->out_use, A_ATOM)) {
+               b->s.k += last->s.k;
+               last->s.code = NOP;
+               done = 0;
+       }
+       /*
+        * and #k       nop
+        * jeq #0  ->   jset #k
+        */
+       if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
+           !ATOMELEM(b->out_use, A_ATOM) && b->s.k == 0) {
+               b->s.k = last->s.k;
+               b->s.code = BPF_JMP|BPF_K|BPF_JSET;
+               last->s.code = NOP;
+               done = 0;
+               opt_not(b);
+       }
+       /*
+        * If the accumulator is a known constant, we can compute the
+        * comparison result.
+        */
+       val = b->val[A_ATOM];
+       if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
+               v = vmap[val].const_val;
+               switch (BPF_OP(b->s.code)) {
+
+               case BPF_JEQ:
+                       v = v == b->s.k;
+                       break;
+
+               case BPF_JGT:
+                       v = v > b->s.k;
+                       break;
+
+               case BPF_JGE:
+                       v = v >= b->s.k;
+                       break;
+
+               case BPF_JSET:
+                       v &= b->s.k;
+                       break;
+
+               default:
+                       abort();
+               }
+               if (JF(b) != JT(b))
+                       done = 0;
+               if (v)
+                       JF(b) = JT(b);
+               else
+                       JT(b) = JF(b);
+       }
+}
+
+/*
+ * Compute the symbolic value of expression of 's', and update
+ * anything it defines in the value table 'val'.  If 'alter' is true,
+ * do various optimizations.  This code would be cleaner if symblic
+ * evaluation and code transformations weren't folded together.
+ */
+static void
+opt_stmt(s, val, alter)
+       struct stmt *s;
+       long val[];
+       int alter;
+{
+       int op;
+       long v;
+
+       switch (s->code) {
+
+       case BPF_LD|BPF_ABS|BPF_W:
+       case BPF_LD|BPF_ABS|BPF_H:
+       case BPF_LD|BPF_ABS|BPF_B:
+               v = F(s->code, s->k, 0L);
+               vstore(s, &val[A_ATOM], v, alter);
+               break;
+
+       case BPF_LD|BPF_IND|BPF_W:
+       case BPF_LD|BPF_IND|BPF_H:
+       case BPF_LD|BPF_IND|BPF_B:
+               v = val[X_ATOM];
+               if (alter && vmap[v].is_const) {
+                       s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
+                       s->k += vmap[v].const_val;
+                       v = F(s->code, s->k, 0L);
+                       done = 0;
+               }
+               else
+                       v = F(s->code, s->k, v);
+               vstore(s, &val[A_ATOM], v, alter);
+               break;
+               
+       case BPF_LD|BPF_LEN:
+               v = F(s->code, 0L, 0L);
+               vstore(s, &val[A_ATOM], v, alter);
+               break;
+
+       case BPF_LD|BPF_IMM:
+               v = K(s->k);
+               vstore(s, &val[A_ATOM], v, alter);
+               break;
+
+       case BPF_LDX|BPF_IMM:
+               v = K(s->k);
+               vstore(s, &val[X_ATOM], v, alter);
+               break;
+
+       case BPF_LDX|BPF_MSH|BPF_B:
+               v = F(s->code, s->k, 0L);
+               vstore(s, &val[X_ATOM], v, alter);
+               break;
+
+       case BPF_ALU|BPF_NEG:
+               if (alter && vmap[val[A_ATOM]].is_const) {
+                       s->code = BPF_LD|BPF_IMM;
+                       s->k = -vmap[val[A_ATOM]].const_val;
+                       val[A_ATOM] = K(s->k);
+               }
+               else
+                       val[A_ATOM] = F(s->code, val[A_ATOM], 0L);
+               break;
+
+       case BPF_ALU|BPF_ADD|BPF_K:
+       case BPF_ALU|BPF_SUB|BPF_K:
+       case BPF_ALU|BPF_MUL|BPF_K:
+       case BPF_ALU|BPF_DIV|BPF_K:
+       case BPF_ALU|BPF_AND|BPF_K:
+       case BPF_ALU|BPF_OR|BPF_K:
+       case BPF_ALU|BPF_LSH|BPF_K:
+       case BPF_ALU|BPF_RSH|BPF_K:
+               op = BPF_OP(s->code);
+               if (alter) {
+                       if (s->k == 0) {
+                               if (op == BPF_ADD || op == BPF_SUB ||
+                                   op == BPF_LSH || op == BPF_RSH ||
+                                   op == BPF_OR) {
+                                       s->code = NOP;
+                                       break;
+                               }
+                               if (op == BPF_MUL || op == BPF_AND) {
+                                       s->code = BPF_LD|BPF_IMM;
+                                       val[A_ATOM] = K(s->k);
+                                       break;
+                               }
+                       }
+                       if (vmap[val[A_ATOM]].is_const) {
+                               fold_op(s, val[A_ATOM], K(s->k));
+                               val[A_ATOM] = K(s->k);
+                               break;
+                       }
+               }
+               val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
+               break;
+
+       case BPF_ALU|BPF_ADD|BPF_X:
+       case BPF_ALU|BPF_SUB|BPF_X:
+       case BPF_ALU|BPF_MUL|BPF_X:
+       case BPF_ALU|BPF_DIV|BPF_X:
+       case BPF_ALU|BPF_AND|BPF_X:
+       case BPF_ALU|BPF_OR|BPF_X:
+       case BPF_ALU|BPF_LSH|BPF_X:
+       case BPF_ALU|BPF_RSH|BPF_X:
+               op = BPF_OP(s->code);
+               if (alter && vmap[val[X_ATOM]].is_const) {
+                       if (vmap[val[A_ATOM]].is_const) {
+                               fold_op(s, val[A_ATOM], val[X_ATOM]);
+                               val[A_ATOM] = K(s->k);
+                       }
+                       else {
+                               s->code = BPF_ALU|BPF_K|op;
+                               s->k = vmap[val[X_ATOM]].const_val;
+                               done = 0;
+                               val[A_ATOM] = 
+                                       F(s->code, val[A_ATOM], K(s->k));
+                       }
+                       break;
+               }
+               /*
+                * Check if we're doing something to an accumulator
+                * that is 0, and simplify.  This may not seem like
+                * much of a simplification but it could open up further
+                * optimizations.
+                * XXX We could also check for mul by 1, and -1, etc.
+                */
+               if (alter && vmap[val[A_ATOM]].is_const
+                   && vmap[val[A_ATOM]].const_val == 0) {
+                       if (op == BPF_ADD || op == BPF_OR || 
+                           op == BPF_LSH || op == BPF_RSH || op == BPF_SUB) {
+                               s->code = BPF_MISC|BPF_TXA;
+                               vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+                               break;
+                       }
+                       else if (op == BPF_MUL || op == BPF_DIV || 
+                                op == BPF_AND) {
+                               s->code = BPF_LD|BPF_IMM;
+                               s->k = 0;
+                               vstore(s, &val[A_ATOM], K(s->k), alter);
+                               break;
+                       }
+                       else if (op == BPF_NEG) {
+                               s->code = NOP;
+                               break;
+                       }
+               }
+               val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]);
+               break;
+
+       case BPF_MISC|BPF_TXA:
+               vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+               break;
+
+       case BPF_LD|BPF_MEM:
+               v = val[s->k];
+               if (alter && vmap[v].is_const) {
+                       s->code = BPF_LD|BPF_IMM;
+                       s->k = vmap[v].const_val;
+                       done = 0;
+               }
+               vstore(s, &val[A_ATOM], v, alter);
+               break;
+               
+       case BPF_MISC|BPF_TAX:
+               vstore(s, &val[X_ATOM], val[A_ATOM], alter);
+               break;
+
+       case BPF_LDX|BPF_MEM:
+               v = val[s->k];
+               if (alter && vmap[v].is_const) {
+                       s->code = BPF_LDX|BPF_IMM;
+                       s->k = vmap[v].const_val;
+                       done = 0;
+               }
+               vstore(s, &val[X_ATOM], v, alter);
+               break;
+
+       case BPF_ST:
+               vstore(s, &val[s->k], val[A_ATOM], alter);
+               break;
+
+       case BPF_STX:
+               vstore(s, &val[s->k], val[X_ATOM], alter);
+               break;
+       }
+}
+
+static void
+deadstmt(s, last)
+       register struct stmt *s;
+       register struct stmt *last[];
+{
+       register int atom;
+
+       atom = atomuse(s);
+       if (atom >= 0) {
+               if (atom == AX_ATOM) {
+                       last[X_ATOM] = 0;
+                       last[A_ATOM] = 0;
+               }
+               else
+                       last[atom] = 0;
+       }
+       atom = atomdef(s);
+       if (atom >= 0) {
+               if (last[atom]) {
+                       done = 0;
+                       last[atom]->code = NOP;
+               }
+               last[atom] = s;
+       }
+}
+
+static void
+opt_deadstores(b)
+       register struct block *b;
+{
+       register struct slist *s;
+       register int atom;
+       struct stmt *last[N_ATOMS];
+
+       bzero((char *)last, sizeof last);
+
+       for (s = b->stmts; s != 0; s = s->next)
+               deadstmt(&s->s, last);
+       deadstmt(&b->s, last);
+
+       for (atom = 0; atom < N_ATOMS; ++atom)
+               if (last[atom] && !ATOMELEM(b->out_use, atom)) {
+                       last[atom]->code = NOP;
+                       done = 0;
+               }
+}
+
+static void
+opt_blk(b, do_stmts)
+       struct block *b;
+{
+       struct slist *s;
+       struct edge *p;
+       int i;
+       long aval;
+
+       /* 
+        * Initialize the atom values.
+        * If we have no predecessors, everything is undefined.
+        * Otherwise, we inherent our values from our predecessors.  
+        * If any register has an ambiguous value (i.e. control paths are
+        * merging) give it the undefined value of 0.
+        */
+       p = b->in_edges;
+       if (p == 0)
+               bzero((char *)b->val, sizeof(b->val));
+       else {
+               bcopy((char *)p->pred->val, (char *)b->val, sizeof(b->val));
+               while (p = p->next) {
+                       for (i = 0; i < N_ATOMS; ++i)
+                               if (b->val[i] != p->pred->val[i])
+                                       b->val[i] = 0;
+               }
+       }
+       aval = b->val[A_ATOM];
+       for (s = b->stmts; s; s = s->next)
+               opt_stmt(&s->s, b->val, do_stmts);
+
+       /*
+        * This is a special case: if we don't use anything from this
+        * block, and we load the accumulator with value that is 
+        * already there, eliminate all the statements.
+        */
+       if (do_stmts && b->out_use == 0 && aval != 0 &&
+           b->val[A_ATOM] == aval)
+               b->stmts = 0;
+       else {
+               opt_peep(b);
+               opt_deadstores(b);
+       }
+       /*
+        * Set up values for branch optimizer.
+        */
+       if (BPF_SRC(b->s.code) == BPF_K)
+               b->oval = K(b->s.k);
+       else
+               b->oval = b->val[X_ATOM];
+       b->et.code = b->s.code;
+       b->ef.code = -b->s.code;
+}
+
+/*
+ * Return true if any register that is used on exit from 'succ', has
+ * an exit value that is different from the corresponding exit value
+ * from 'b'.
+ */
+static int 
+use_conflict(b, succ)
+       struct block *b, *succ;
+{
+       int atom;
+       atomset use = succ->out_use;
+
+       if (use == 0)
+               return 0;
+
+       for (atom = 0; atom < N_ATOMS; ++atom)
+               if (ATOMELEM(use, atom))
+                       if (b->val[atom] != succ->val[atom])
+                               return 1;
+       return 0;
+}
+
+struct block *
+fold_edge(child, ep)
+       struct block *child;
+       struct edge *ep;
+{
+       int sense;
+       int aval0, aval1, oval0, oval1;
+       int code = ep->code;
+
+       if (code < 0) {
+               code = -code;
+               sense = 0;
+       } else
+               sense = 1;
+
+       if (child->s.code != code)
+               return 0;
+
+       aval0 = child->val[A_ATOM];
+       oval0 = child->oval;
+       aval1 = ep->pred->val[A_ATOM];
+       oval1 = ep->pred->oval;
+
+       if (aval0 != aval1)
+               return 0;
+
+       if (oval0 == oval1)
+               /*
+                * The operands are identical, so the 
+                * result is true if a true branch was
+                * taken to get here, otherwise false.
+                */
+               return sense ? JT(child) : JF(child);
+
+       if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
+               /* 
+                * At this point, we only know the comparison if we
+                * came down the true branch, and it was an equility
+                * comparison with a constant.  We rely on the fact that
+                * distinct constants have distinct value numbers.
+                */
+               return JF(child);
+
+       return 0;
+}
+
+static void
+opt_j(ep)
+       struct edge *ep;
+{
+       register int i, k;
+       register struct block *target;
+
+       if (JT(ep->succ) == 0)
+               return;
+
+       if (JT(ep->succ) == JF(ep->succ)) {
+               /*
+                * Common branch targets can be eliminated, provided
+                * there is no data dependency.
+                */
+               if (!use_conflict(ep->pred, ep->succ->et.succ)) {
+                       done = 0;
+                       ep->succ = JT(ep->succ);
+               }
+       }
+       /*
+        * For each edge dominator that matches the successor of this
+        * edge, promote the edge succesor to the its grandchild.
+        *
+        * XXX We violate the set abstraction here in favor a reasonbly
+        * efficient loop.
+        */
+ top:
+       for (i = 0; i < edgewords; ++i) {
+               register u_long x = ep->edom[i];
+
+               while (x != 0) {
+                       k = ffs(x) - 1;
+                       x &=~ 1 << k;
+                       k += i * BITS_PER_WORD;
+
+                       target = fold_edge(ep->succ, edges[k]);
+                       /*
+                        * Check that there is no data dependency between 
+                        * nodes that will be violated if we move the edge.
+                        */
+                       if (target != 0 && !use_conflict(ep->pred, target)) {
+                               done = 0;
+                               ep->succ = target;
+                               if (JT(target) != 0)
+                                       /*
+                                        * Start over unless we hit a leaf.
+                                        */
+                                       goto top;
+                               return;
+                       }
+               }
+       }
+}                      
+
+
+static void
+or_pullup(b)
+       struct block *b;
+{
+       int val, at_top;
+       struct block *pull;
+       struct block **diffp, **samep;
+       struct edge *ep;
+
+       ep = b->in_edges;
+       if (ep == 0)
+               return;
+
+       /*
+        * Make sure each predecessor loads the same value.
+        * XXX why?
+        */
+       val = ep->pred->val[A_ATOM];
+       for (ep = ep->next; ep != 0; ep = ep->next)
+               if (val != ep->pred->val[A_ATOM])
+                       return;
+
+       if (JT(b->in_edges->pred) == b)
+               diffp = &JT(b->in_edges->pred);
+       else
+               diffp = &JF(b->in_edges->pred);
+
+       at_top = 1;
+       while (1) {
+               if (*diffp == 0)
+                       return;
+
+               if (JT(*diffp) != JT(b))
+                       return;
+
+               if (!SET_MEMBER((*diffp)->dom, b->id))
+                       return;
+
+               if ((*diffp)->val[A_ATOM] != val)
+                       break;
+
+               diffp = &JF(*diffp);
+               at_top = 0;
+       }
+       samep = &JF(*diffp);
+       while (1) {
+               if (*samep == 0)
+                       return;
+
+               if (JT(*samep) != JT(b))
+                       return;
+
+               if (!SET_MEMBER((*samep)->dom, b->id))
+                       return;
+
+               if ((*samep)->val[A_ATOM] == val)
+                       break;
+
+               /* XXX Need to check that there are no data dependencies
+                  between dp0 and dp1.  Currently, the code generator
+                  will not produce such dependencies. */
+               samep = &JF(*samep);
+       }
+#ifdef notdef
+       /* XXX This doesn't cover everything. */
+       for (i = 0; i < N_ATOMS; ++i)
+               if ((*samep)->val[i] != pred->val[i])
+                       return;
+#endif
+       /* Pull up the node. */
+       pull = *samep;
+       *samep = JF(pull);
+       JF(pull) = *diffp;
+       
+       /*
+        * At the top of the chain, each predecessor needs to point at the
+        * pulled up node.  Inside the chain, there is only one predecessor
+        * to worry about.
+        */
+       if (at_top) {
+               for (ep = b->in_edges; ep != 0; ep = ep->next) {
+                       if (JT(ep->pred) == b)
+                               JT(ep->pred) = pull;
+                       else
+                               JF(ep->pred) = pull;
+               }
+       }
+       else
+               *diffp = pull;
+
+       done = 0;
+}
+       
+static void
+and_pullup(b)
+       struct block *b;
+{
+       int val, at_top;
+       struct block *pull;
+       struct block **diffp, **samep;
+       struct edge *ep;
+
+       ep = b->in_edges;
+       if (ep == 0)
+               return;
+
+       /*
+        * Make sure each predecessor loads the same value.
+        */
+       val = ep->pred->val[A_ATOM];
+       for (ep = ep->next; ep != 0; ep = ep->next)
+               if (val != ep->pred->val[A_ATOM])
+                       return;
+
+       if (JT(b->in_edges->pred) == b)
+               diffp = &JT(b->in_edges->pred);
+       else
+               diffp = &JF(b->in_edges->pred);
+
+       at_top = 1;
+       while (1) {
+               if (*diffp == 0)
+                       return;
+
+               if (JF(*diffp) != JF(b))
+                       return;
+
+               if (!SET_MEMBER((*diffp)->dom, b->id))
+                       return;
+
+               if ((*diffp)->val[A_ATOM] != val)
+                       break;
+
+               diffp = &JT(*diffp);
+               at_top = 0;
+       }
+       samep = &JT(*diffp);
+       while (1) {
+               if (*samep == 0)
+                       return;
+
+               if (JF(*samep) != JF(b))
+                       return;
+
+               if (!SET_MEMBER((*samep)->dom, b->id))
+                       return;
+
+               if ((*samep)->val[A_ATOM] == val)
+                       break;
+
+               /* XXX Need to check that there are no data dependencies
+                  between diffp and samep.  Currently, the code generator
+                  will not produce such dependencies. */
+               samep = &JT(*samep);
+       }
+#ifdef notdef
+       /* XXX This doesn't cover everything. */
+       for (i = 0; i < N_ATOMS; ++i)
+               if ((*samep)->val[i] != pred->val[i])
+                       return;
+#endif
+       /* Pull up the node. */
+       pull = *samep;
+       *samep = JT(pull);
+       JT(pull) = *diffp;
+       
+       /*
+        * At the top of the chain, each predecessor needs to point at the
+        * pulled up node.  Inside the chain, there is only one predecessor
+        * to worry about.
+        */
+       if (at_top) {
+               for (ep = b->in_edges; ep != 0; ep = ep->next) {
+                       if (JT(ep->pred) == b)
+                               JT(ep->pred) = pull;
+                       else
+                               JF(ep->pred) = pull;
+               }
+       }
+       else
+               *diffp = pull;
+
+       done = 0;
+}
+
+static void
+opt_blks(root, do_stmts)
+       struct block *root;
+{
+       int i, maxlevel;
+       struct block *p;
+
+       init_val();
+       maxlevel = root->level;
+       for (i = maxlevel; i >= 0; --i)
+               for (p = levels[i]; p; p = p->link)
+                       opt_blk(p, do_stmts);
+
+       if (do_stmts)
+               /* 
+                * No point trying to move branches; it can't possibly
+                * make a difference at this point.
+                */
+               return;
+
+       for (i = 1; i <= maxlevel; ++i) {
+               for (p = levels[i]; p; p = p->link) {
+                       opt_j(&p->et);
+                       opt_j(&p->ef);
+               }
+       }
+       for (i = 1; i <= maxlevel; ++i) {
+               for (p = levels[i]; p; p = p->link) {
+                       or_pullup(p);
+                       and_pullup(p);
+               }
+       }
+}
+
+static inline void
+link_inedge(parent, child)
+       struct edge *parent;
+       struct block *child;
+{
+       parent->next = child->in_edges;
+       child->in_edges = parent;
+}      
+
+static void
+find_inedges(root)
+       struct block *root;
+{
+       int i;
+       struct block *b;
+       struct edge *ep;
+
+       for (i = 0; i < n_blocks; ++i)
+               blocks[i]->in_edges = 0;
+
+       /*
+        * Traverse the graph, adding each edge to the predecessor
+        * list of its sucessors.  Skip the leaves (i.e. level 0).
+        */
+       for (i = root->level; i > 0; --i) {
+               for (b = levels[i]; b != 0; b = b->link) {
+                       link_inedge(&b->et, JT(b));
+                       link_inedge(&b->ef, JF(b));
+               }
+       }
+}
+
+static void
+opt_root(b)
+       struct block **b;
+{
+       struct slist *tmp, *s;
+
+       s = (*b)->stmts;
+       (*b)->stmts = 0;
+       while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
+               *b = JT(*b);
+
+       tmp = (*b)->stmts;
+       if (tmp != 0)
+               sappend(s, tmp);
+       (*b)->stmts = s;
+}
+
+static void
+opt_loop(root, do_stmts)
+       struct block *root;
+       int do_stmts;
+{
+       int passes = 0;
+#ifdef BDEBUG
+       if (dflag > 1)
+               opt_dump(root);
+#endif
+       do {
+               done = 1;
+               find_levels(root);
+               find_dom(root);
+               find_closure(root);
+               find_inedges(root);
+               find_ud(root);
+               find_edom(root);
+               opt_blks(root, do_stmts);
+#ifdef BDEBUG
+               if (dflag > 1)
+                       opt_dump(root);
+#endif
+       } while (!done);
+}
+
+/*
+ * Optimize the filter code in its dag representation.
+ */
+void
+optimize(rootp)
+       struct block **rootp;
+{
+       struct block *root;
+
+       root = *rootp;
+
+       opt_init(root);
+       opt_loop(root, 0);
+       opt_loop(root, 1);
+       intern_blocks(root);
+       opt_root(rootp);
+       opt_cleanup();
+}
+
+static void
+make_marks(p)
+       struct block *p;
+{
+       if (!isMarked(p)) {
+               Mark(p);
+               if (BPF_CLASS(p->s.code) != BPF_RET) {
+                       make_marks(JT(p));
+                       make_marks(JF(p));
+               }
+       }
+}
+
+/*
+ * Mark code array such that isMarked(i) is true
+ * only for nodes that are alive.
+ */
+static void
+mark_code(p)
+       struct block *p;
+{
+       cur_mark += 1;
+       make_marks(p);
+}
+
+/*
+ * True iff the two stmt lists load the same value from the packet into
+ * the accumulator.
+ */
+static int
+eq_slist(x, y)
+       struct slist *x, *y;
+{
+       while (1) {
+               while (x && x->s.code == NOP)
+                       x = x->next;
+               while (y && y->s.code == NOP)
+                       y = y->next;
+               if (x == 0)
+                       return y == 0;
+               if (y == 0)
+                       return x == 0;
+               if (x->s.code != y->s.code || x->s.k != y->s.k)
+                       return 0;
+               x = x->next;
+               y = y->next;
+       }
+}
+
+static inline int
+eq_blk(b0, b1)
+       struct block *b0, *b1;
+{
+       if (b0->s.code == b1->s.code &&
+           b0->s.k == b1->s.k &&
+           b0->et.succ == b1->et.succ && 
+           b0->ef.succ == b1->ef.succ)
+               return eq_slist(b0->stmts, b1->stmts);
+       return 0;
+}
+
+static void
+intern_blocks(root)
+       struct block *root;
+{
+       struct block *p;
+       int i, j;
+       int done;
+ top:
+       done = 1;
+       for (i = 0; i < n_blocks; ++i)
+               blocks[i]->link = 0;
+
+       mark_code(root);
+
+       for (i = n_blocks - 1; --i >= 0; ) {
+               if (!isMarked(blocks[i]))
+                       continue;
+               for (j = i + 1; j < n_blocks; ++j) {
+                       if (!isMarked(blocks[j]))
+                               continue;
+                       if (eq_blk(blocks[i], blocks[j])) {
+                               blocks[i]->link = blocks[j]->link ?
+                                       blocks[j]->link : blocks[j];
+                               break;
+                       }
+               }
+       }
+       for (i = 0; i < n_blocks; ++i) {
+               p = blocks[i];
+               if (JT(p) == 0)
+                       continue;
+               if (JT(p)->link) {
+                       done = 0;
+                       JT(p) = JT(p)->link;
+               }
+               if (JF(p)->link) {
+                       done = 0;
+                       JF(p) = JF(p)->link;
+               }
+       }
+       if (!done)
+               goto top;
+}
+
+static void
+opt_cleanup()
+{
+       free((void *)vnode_base);
+       free((void *)vmap);
+       free((void *)edges);
+       free((void *)space);
+       free((void *)levels);
+       free((void *)blocks);
+}
+
+/*
+ * Return the number of stmts in 's'.
+ */
+static int
+slength(s)
+       struct slist *s;
+{
+       int n = 0;
+
+       for (; s; s = s->next)
+               if (s->s.code != NOP)
+                       ++n;
+       return n;
+}
+
+/*
+ * Return the number of nodes reachable by 'p'.
+ * All nodes should be initially unmarked.
+ */
+static int
+count_blocks(p)
+       struct block *p;
+{
+       if (p == 0 || isMarked(p))
+               return 0;
+       Mark(p);
+       return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;
+}      
+
+/*
+ * Do a depth first search on the flow graph, numbering the
+ * the basic blocks, and entering them into the 'blocks' array.`
+ */
+static void
+number_blks_r(p)
+       struct block *p;
+{
+       int n;
+
+       if (p == 0 || isMarked(p))
+               return;
+
+       Mark(p);
+       n = n_blocks++;
+       p->id = n;
+       blocks[n] = p;
+
+       number_blks_r(JT(p));
+       number_blks_r(JF(p));
+}
+
+/*
+ * Return the number of stmts in the flowgraph reachable by 'p'.
+ * The nodes should be unmarked before calling.
+ */
+static int
+count_stmts(p)
+       struct block *p;
+{
+       int n;
+
+       if (p == 0 || isMarked(p))
+               return 0;
+       Mark(p);
+       n = count_stmts(JT(p)) + count_stmts(JF(p));
+       return slength(p->stmts) + n + 1;
+}
+
+/*
+ * Allocate memory.  All allocation is done before optimization
+ * is begun.  A linear bound on the size of all data structures is computed
+ * from the total number of blocks and/or statements.
+ */
+static void
+opt_init(root)
+       struct block *root;
+{
+       u_long *p;
+       int i, n, max_stmts;
+
+       /*
+        * First, count the blocks, so we can malloc an array to map
+        * block number to block.  Then, put the blocks into the array.
+        */
+       unMarkAll();
+       n = count_blocks(root);
+       blocks = (struct block **)malloc(n * sizeof(*blocks));
+       unMarkAll();
+       n_blocks = 0;
+       number_blks_r(root);
+
+       n_edges = 2 * n_blocks;
+       edges = (struct edge **)malloc(n_edges * sizeof(*edges));
+
+       /*
+        * The number of levels is bounded by the number of nodes.
+        */
+       levels = (struct block **)malloc(n_blocks * sizeof(*levels));
+
+       edgewords = n_edges / (8 * sizeof(u_long)) + 1;
+       nodewords = n_blocks / (8 * sizeof(u_long)) + 1;
+
+       /* XXX */
+       space = (u_long *)malloc(2 * n_blocks * nodewords * sizeof(*space)
+                                + n_edges * edgewords * sizeof(*space));
+       p = space;
+       all_dom_sets = p;
+       for (i = 0; i < n; ++i) {
+               blocks[i]->dom = p;
+               p += nodewords;
+       }
+       all_closure_sets = p;
+       for (i = 0; i < n; ++i) {
+               blocks[i]->closure = p;
+               p += nodewords;
+       }
+       all_edge_sets = p;
+       for (i = 0; i < n; ++i) {
+               register struct block *b = blocks[i];
+
+               b->et.edom = p;
+               p += edgewords;
+               b->ef.edom = p;
+               p += edgewords;
+               b->et.id = i;
+               edges[i] = &b->et;
+               b->ef.id = n_blocks + i;
+               edges[n_blocks + i] = &b->ef;
+               b->et.pred = b;
+               b->ef.pred = b;
+       }
+       max_stmts = 0;
+       for (i = 0; i < n; ++i)
+               max_stmts += slength(blocks[i]->stmts) + 1;
+       /*
+        * We allocate at most 3 value numbers per statement,
+        * so this is an upper bound on the number of valnodes
+        * we'll need.
+        */
+       maxval = 3 * max_stmts;
+       vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap));
+       vnode_base = (struct valnode *)malloc(maxval * sizeof(*vmap));
+}
+
+/*
+ * Some pointers used to convert the basic block form of the code,
+ * into the array form that BPF requires.  'fstart' will point to
+ * the malloc'd array while 'ftail' is used during the recursive traversal.
+ */
+static struct bpf_insn *fstart;
+static struct bpf_insn *ftail;
+
+#ifdef BDEBUG
+int bids[1000];
+#endif
+
+static void
+convert_code_r(p)
+       struct block *p;
+{
+       struct bpf_insn *dst;
+       struct slist *src;
+       int slen;
+       u_int off;
+
+       if (p == 0 || isMarked(p))
+               return;
+       Mark(p);
+
+       convert_code_r(JF(p));
+       convert_code_r(JT(p));
+
+       slen = slength(p->stmts);
+       dst = ftail -= slen + 1;
+
+       p->offset = dst - fstart;
+
+       for (src = p->stmts; src; src = src->next) {
+               if (src->s.code == NOP)
+                       continue;
+               dst->code = (u_short)src->s.code;
+               dst->k = src->s.k;
+               ++dst;
+       }
+#ifdef BDEBUG
+       bids[dst - fstart] = p->id + 1;
+#endif
+       dst->code = (u_short)p->s.code;
+       dst->k = p->s.k;
+       if (JT(p)) {
+               off = JT(p)->offset - (p->offset + slen) - 1;
+               if (off >= 256) 
+                       error("long jumps not supported");
+               dst->jt = off;
+               off = JF(p)->offset - (p->offset + slen) - 1;
+               if (off >= 256) 
+                       error("long jumps not supported");
+               dst->jf = off;
+       }
+}
+       
+
+/*
+ * Convert flowgraph intermediate representation to the
+ * BPF array representation.  Set *lenp to the number of instructions.
+ */
+struct bpf_insn *
+icode_to_fcode(root, lenp)
+       struct block *root;
+       int *lenp;
+{
+       int n;
+       struct bpf_insn *fp;
+       
+       unMarkAll();
+       n = *lenp = count_stmts(root);
+
+       fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
+       bzero((char *)fp, sizeof(*fp) * n);
+       fstart = fp;
+       ftail = fp + n;
+
+       unMarkAll();
+       convert_code_r(root);
+
+       return fp;
+}
+
+#ifdef BDEBUG
+opt_dump(root)
+       struct block *root;
+{
+       struct bpf_program f;
+       
+       bzero(bids, sizeof bids);
+       f.bf_insns = icode_to_fcode(root, &f.bf_len);
+       bpf_dump(&f, 1);
+       putchar('\n');
+       free((char *)f.bf_insns);
+}
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/os.c b/usr/src/contrib/tcpdump/tcpdump/os.c
new file mode 100644 (file)
index 0000000..856fb5a
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: os-bsd.c,v 1.2 90/09/21 02:12:17 mccanne Exp $ (LBL)";
+#endif
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/os.h b/usr/src/contrib/tcpdump/tcpdump/os.h
new file mode 100644 (file)
index 0000000..e0d01cf
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: os-bsd.h,v 1.15 91/05/05 23:59:11 mccanne Exp $ (LBL)
+ */
+
+#include <sys/param.h>
+
+#ifndef BSD
+#define BSD
+#endif
+
+#define SHA(ap) ((ap)->arp_sha)
+#define SPA(ap) ((ap)->arp_spa)
+#define THA(ap) ((ap)->arp_tha)
+#define TPA(ap) ((ap)->arp_tpa)
+
+#define EDST(ep) ((ep)->ether_dhost)
+#define ESRC(ep) ((ep)->ether_shost)
+
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP 0x8035
+#endif
+
+#ifndef        IPPROTO_ND
+/* From <netinet/in.h> on a Sun somewhere. */
+#define        IPPROTO_ND      77
+#endif
+
+#ifndef REVARP_REQUEST
+#define REVARP_REQUEST 3
+#endif
+#ifndef REVARP_REPLY
+#define REVARP_REPLY 4
+#endif
+
+/* newish RIP commands */
+#ifndef        RIPCMD_POLL
+#define        RIPCMD_POLL 5
+#endif
+#ifndef        RIPCMD_POLLENTRY
+#define        RIPCMD_POLLENTRY 6
+#endif
+
+/*
+ * Map BSD names to SunOS names.
+ */
+#if BSD >= 199006
+#define RFS_NULL       NFSPROC_NULL
+#define RFS_GETATTR    NFSPROC_GETATTR
+#define RFS_SETATTR    NFSPROC_SETATTR
+#define RFS_ROOT       NFSPROC_ROOT
+#define RFS_LOOKUP     NFSPROC_LOOKUP
+#define RFS_READLINK   NFSPROC_READLINK
+#define RFS_READ       NFSPROC_READ
+#define RFS_WRITECACHE NFSPROC_WRITECACHE
+#define RFS_WRITE      NFSPROC_WRITE
+#define RFS_CREATE     NFSPROC_CREATE
+#define RFS_REMOVE     NFSPROC_REMOVE
+#define RFS_RENAME     NFSPROC_RENAME
+#define RFS_LINK       NFSPROC_LINK
+#define RFS_SYMLINK    NFSPROC_SYMLINK
+#define RFS_MKDIR      NFSPROC_MKDIR
+#define RFS_RMDIR      NFSPROC_RMDIR
+#define RFS_READDIR    NFSPROC_READDIR
+#define RFS_STATFS     NFSPROC_STATFS
+#define RFS_NPROC      NFSPROC_NPROC
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/ospf.h b/usr/src/contrib/tcpdump/tcpdump/ospf.h
new file mode 100644 (file)
index 0000000..e3a3a6d
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1991 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
+ */
+#define        OSPF_TYPE_UMD   0       /* UMd's special monitoring packets */
+#define        OSPF_TYPE_HELLO 1       /* Hello */
+#define        OSPF_TYPE_DB    2       /* Database Description */
+#define        OSPF_TYPE_LSR   3       /* Link State Request */
+#define        OSPF_TYPE_LSU   4       /* Link State Update */
+#define        OSPF_TYPE_LSA   5       /* Link State Ack */
+#define        OSPF_TYPE_MAX   6
+
+/* Options *_options   */
+#define OSPF_OPTION_T  0x01    /* T bit: TOS support   */
+#define OSPF_OPTION_E  0x02    /* E bit: External routes advertised    */
+#define        OSPF_OPTION_MC  0x04    /* MC bit: Multicast capable */
+
+/* ospf_authtype       */
+#define        OSPF_AUTH_NONE          0       /* No auth-data */
+#define        OSPF_AUTH_SIMPLE        1       /* Simple password */
+
+/* db_flags    */
+#define        OSPF_DB_INIT            0x04        /*  */
+#define        OSPF_DB_MORE            0x02
+#define        OSPF_DB_MASTER          0x01
+
+/* ls_type     */
+#define        LS_TYPE_ROUTER          1   /* router link */
+#define        LS_TYPE_NETWORK         2   /* network link */
+#define        LS_TYPE_SUM_IP          3   /* summary link */
+#define        LS_TYPE_SUM_ABR         4   /* summary area link */
+#define        LS_TYPE_ASE             5   /* ASE  */
+#define        LS_TYPE_GROUP           6   /* Group membership (multicast */
+                                   /* extensions 23 July 1991) */
+#define        LS_TYPE_MAX             7
+
+/*************************************************
+ *
+ * is the above a bug in the documentation?
+ *
+ *************************************************/
+
+/* rla_link.link_type  */
+#define        RLA_TYPE_ROUTER         1   /* point-to-point to another router */
+#define        RLA_TYPE_TRANSIT        2   /* connection to transit network    */
+#define        RLA_TYPE_STUB           3   /* connection to stub network       */
+#define RLA_TYPE_VIRTUAL       4   /* virtual link                     */
+
+/* rla_flags   */
+#define        RLA_FLAG_B      0x01
+#define        RLA_FLAG_E      0x02
+#define        RLA_FLAG_W1     0x04
+#define        RLA_FLAG_W2     0x08
+
+/* sla_tosmetric breakdown     */
+#define        SLA_MASK_TOS            0x7f000000
+#define        SLA_MASK_METRIC         0x00ffffff
+#define SLA_SHIFT_TOS          24
+
+/* asla_tosmetric breakdown    */
+#define        ASLA_FLAG_EXTERNAL      0x80000000
+#define        ASLA_MASK_TOS           0x7f000000
+#define        ASLA_SHIFT_TOS          24
+#define        ASLA_MASK_METRIC        0x00ffffff
+
+/* multicast vertex type */
+#define        MCLA_VERTEX_ROUTER      1
+#define        MCLA_VERTEX_NETWORK     2
+
+/* link state advertisement header */
+struct lsa_hdr {
+    u_short ls_age;
+    u_char ls_options;
+    u_char ls_type;
+    struct in_addr ls_stateid;
+    struct in_addr ls_router;
+    u_long ls_seq;
+    u_short ls_chksum;
+    u_short ls_length;
+} ;
+
+/* link state advertisement */
+struct lsa {
+    struct lsa_hdr ls_hdr;
+
+    /* Link state types */
+    union {
+       /* Router links advertisements */
+       struct {
+           u_char rla_flags;
+           u_char rla_zero[1];
+           u_short rla_count;
+           struct rlalink {
+               struct in_addr link_id;
+               struct in_addr link_data;
+               u_char link_type;
+               u_char link_toscount;
+               u_short link_tos0metric;
+           } rla_link[1];              /* may repeat   */
+       } un_rla;
+
+       /* Network links advertisements */
+       struct {
+           struct in_addr nla_mask;
+           struct in_addr nla_router[1];       /* may repeat   */
+       } un_nla;
+
+       /* Summary links advertisements */
+       struct {
+           struct in_addr sla_mask;
+           u_long sla_tosmetric[1];    /* may repeat   */
+       } un_sla;
+
+       /* AS external links advertisements */
+       struct {
+           struct in_addr asla_mask;
+           struct aslametric {
+               u_long asla_tosmetric;
+               struct in_addr asla_forward;
+               struct in_addr asla_tag;
+           } asla_metric[1];           /* may repeat   */
+       } un_asla;
+
+       /* Multicast group membership */
+       struct mcla {
+           u_long mcla_vtype;
+           struct in_addr mcla_vid;
+       } un_mcla[1];
+    } lsa_un;
+} ;
+
+
+/*
+ * TOS metric struct (will be 0 or more in router links update)
+ */
+struct tos_metric {
+    u_char tos_type;
+    u_char tos_zero;
+    u_short tos_metric;
+} ;
+
+#define        OSPF_AUTH_SIZE  8
+
+/*
+ * the main header
+ */
+struct ospfhdr {
+    u_char ospf_version;
+    u_char ospf_type;
+    u_short ospf_len;
+    struct in_addr ospf_routerid;
+    struct in_addr ospf_areaid;
+    u_short ospf_chksum;
+    u_short ospf_authtype;
+    u_char ospf_authdata[OSPF_AUTH_SIZE];
+    union {
+
+       /* Hello packet */
+       struct {
+           struct in_addr hello_mask;
+           u_short hello_helloint;
+           u_char hello_options;
+           u_char hello_priority;
+           u_long hello_deadint;      
+           struct in_addr hello_dr;
+           struct in_addr hello_bdr;
+           struct in_addr hello_neighbor[1]; /* may repeat     */
+       } un_hello;
+
+       /* Database Description packet */
+       struct {
+           u_char db_zero[2];
+           u_char db_options;
+           u_char db_flags;
+           u_long db_seq;
+           struct lsa_hdr db_lshdr[1]; /* may repeat   */
+       } un_db;
+
+       /* Link State Request */
+       struct lsr {
+           u_long ls_type;
+           struct in_addr ls_stateid;
+           struct in_addr ls_router;
+       } un_lsr[1];            /* may repeat   */
+
+       /* Link State Update */
+       struct {
+           u_long lsu_count;
+           struct lsa lsu_lsa[1]; /* may repeat        */
+       } un_lsu;
+
+       /* Link State Acknowledment */
+       struct {
+           struct lsa_hdr lsa_lshdr[1]; /* may repeat  */
+       } un_lsa ;
+    } ospf_un ;
+} ;
+
+#define        ospf_hello      ospf_un.un_hello
+#define        ospf_db         ospf_un.un_db
+#define        ospf_lsr        ospf_un.un_lsr
+#define        ospf_lsu        ospf_un.un_lsu
+#define        ospf_lsa        ospf_un.un_lsa
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/pcap.c b/usr/src/contrib/tcpdump/tcpdump/pcap.c
new file mode 100644 (file)
index 0000000..04c9695
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static  char rcsid[] =
+    "@(#)$Header: pcap-bpf.c,v 1.29 92/06/02 17:57:29 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>                 /* optionally get BSD define */
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <string.h>
+
+#include "interface.h"
+
+extern int errno;
+
+static void
+bpf_stats(fd)
+       int fd;
+{
+       struct bpf_stat s;
+       
+       if (ioctl(fd, BIOCGSTATS, &s) < 0)
+               return;
+
+       (void)fflush(stdout);
+       (void)fprintf(stderr, "%d packets received by filter\n", s.bs_recv);
+       (void)fprintf(stderr, "%d packets dropped by kernel\n", s.bs_drop);
+}
+
+void
+readloop(cnt, if_fd, fp, printit)
+       int cnt;
+       int if_fd;
+       struct bpf_program *fp;
+       void (*printit)();
+{
+       u_char *buf;
+       u_int bufsize;
+       int cc;
+
+       if (ioctl(if_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) {
+               perror("tcpdump: BIOCGBLEN");
+               exit(1);
+       }
+       buf = (u_char *)malloc(bufsize);
+
+       if (ioctl(if_fd, BIOCSETF, (caddr_t)fp) < 0) {
+               perror("tcpdump: BIOCSETF");
+               exit(1);
+       }
+       while (1) {
+               register u_char *bp, *ep;
+
+               if ((cc = read(if_fd, (char *)buf, (int)bufsize)) < 0) {
+                       /* Don't choke when we get ptraced */
+                       if (errno == EINTR)
+                               continue;
+#if defined(sun) && !defined(BSD)
+                       /*
+                        * Due to a SunOS bug, after 2^31 bytes, the kernel
+                        * file offset overflows and read fails with EINVAL.
+                        * The lseek() to 0 will fix things.
+                        */
+                       if (errno == EINVAL &&
+                           (long)(tell(if_fd) + bufsize) < 0) {
+                               (void)lseek(if_fd, 0, 0);
+                               continue;
+                       }
+#endif
+                       perror("tcpdump: read");
+                       exit(1);
+               }
+               /*
+                * Loop through each packet.
+                */
+#define bhp ((struct bpf_hdr *)bp)
+               bp = buf;
+               ep = bp + cc;
+               while (bp < ep) {
+                       register int caplen, hdrlen;
+                       if (cnt >= 0 && --cnt < 0)
+                               goto out;
+                       (*printit)(bp + (hdrlen = bhp->bh_hdrlen),
+                                  &bhp->bh_tstamp, bhp->bh_datalen,
+                                  caplen = bhp->bh_caplen);
+                       bp += BPF_WORDALIGN(caplen + hdrlen);
+               }
+#undef bhp
+       }
+ out:
+       wrapup(if_fd);
+}
+
+wrapup(fd)
+       int fd;
+{
+       bpf_stats(fd);
+       close(fd);
+}
+
+static inline int
+bpf_open()
+{
+       int fd;
+       int n = 0;
+       char device[sizeof "/dev/bpf000"];
+
+       /*
+        * Go through all the minors and find one that isn't in use.
+        */
+       do {
+               (void)sprintf(device, "/dev/bpf%d", n++);
+               fd = open(device, O_RDONLY);
+       } while (fd < 0 && errno == EBUSY);
+
+       if (fd < 0) {
+               (void) fprintf(stderr, "tcpdump: ");
+               perror(device);
+               exit(-1);
+       }
+       return fd;
+}
+
+int
+initdevice(device, pflag, linktype)
+       char *device;
+       int pflag;
+       int *linktype;
+{
+       struct timeval timeout;
+       int if_fd;
+       struct ifreq ifr;
+       struct bpf_version bv;
+       
+       if_fd = bpf_open();
+
+       if (ioctl(if_fd, BIOCVERSION, (caddr_t)&bv) < 0)
+               warning("kernel bpf interpreter may be out of date");
+       else if (bv.bv_major != BPF_MAJOR_VERSION ||
+                bv.bv_minor < BPF_MINOR_VERSION)
+               error("requires bpf language %d.%d or higher; kernel is %d.%d",
+                     BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+                     bv.bv_major, bv.bv_minor);
+
+       (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(if_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+               (void) fprintf(stderr, "tcpdump: BIOCSETIF: ");
+               perror(device);
+               exit(-1);
+       }
+       /* Get the data link layer type. */
+       if (ioctl(if_fd, BIOCGDLT, (caddr_t)linktype) < 0) {
+               perror("tcpdump: BIOCGDLT");
+               exit(-1);
+       }
+       /* set timeout */
+       timeout.tv_sec = 1;
+       timeout.tv_usec = 0;
+       if (ioctl(if_fd, BIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
+               perror("tcpdump: BIOCSRTIMEOUT");
+               exit(-1);
+       }
+       /* set promiscuous mode if requested, but only for broadcast nets */
+       if (pflag == 0) {
+               switch (*linktype) {
+
+               case DLT_SLIP:
+               case DLT_PPP:
+               case DLT_NULL:
+                       break;
+
+               default:
+                       if (ioctl(if_fd, BIOCPROMISC, (void *)0) < 0) {
+                               perror("tcpdump: BIOCPROMISC");
+                               exit(-1);
+                       }
+               }
+       }
+       return(if_fd);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-arp.c b/usr/src/contrib/tcpdump/tcpdump/print-arp.c
new file mode 100644 (file)
index 0000000..3f0671a
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-arp.c,v 1.16 91/04/19 10:45:56 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+arp_print(ap, length, caplen)
+       register struct ether_arp *ap;
+       int length;
+       int caplen;
+{
+       if ((u_char *)(ap + 1) > snapend) {
+               printf("[|arp]");
+               return;
+       }
+       if (length < sizeof(struct ether_arp)) {
+               (void)printf("truncated-arp");
+               default_print((u_short *)ap, length);
+               return;
+       }
+
+       NTOHS(ap->arp_hrd);
+       NTOHS(ap->arp_pro);
+       NTOHS(ap->arp_op);
+
+       if (ap->arp_hrd != ARPHRD_ETHER
+           || (ap->arp_pro != ETHERTYPE_IP
+               && ap->arp_pro != ETHERTYPE_TRAIL)
+           || ap->arp_hln != sizeof(SHA(ap))
+           || ap->arp_pln != sizeof(SPA(ap))) {
+               (void)printf("arp-req #%d for proto #%d (%d) hardware %d (%d)",
+                               ap->arp_op, ap->arp_pro, ap->arp_pln,
+                               ap->arp_hrd, ap->arp_hln);
+               return;
+       }
+       if (ap->arp_pro == ETHERTYPE_TRAIL)
+               (void)printf("trailer");
+       switch (ap->arp_op) {
+
+       case ARPOP_REQUEST:
+               (void)printf("arp who-has %s tell %s",
+                       ipaddr_string(TPA(ap)),
+                       ipaddr_string(SPA(ap)));
+               break;
+
+       case ARPOP_REPLY:
+               (void)printf("arp reply %s is-at %s",
+                       ipaddr_string(SPA(ap)),
+                       etheraddr_string(SHA(ap)));
+               break;
+
+       case REVARP_REQUEST:
+               (void)printf("rarp who-is %s tell %s",
+                       etheraddr_string(THA(ap)),
+                       etheraddr_string(SHA(ap)));
+               break;
+
+       case REVARP_REPLY:
+               (void)printf("rarp reply %s at %s",
+                       etheraddr_string(THA(ap)),
+                       ipaddr_string(TPA(ap)));
+               break;
+
+       default:
+               (void)printf("arp-%d", ap->arp_op);
+               default_print((u_short *)ap, caplen);
+               break;
+       }
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-atalk.c b/usr/src/contrib/tcpdump/tcpdump/print-atalk.c
new file mode 100644 (file)
index 0000000..203585e
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print AppleTalk packets.
+ */
+#ifndef lint
+static  char rcsid[] =
+       "@(#)$Header: print-atalk.c,v 1.22 92/03/26 14:15:34 mccanne Exp $ (LBL)";
+#endif
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "appletalk.h"
+#include <strings.h>
+#include "extract.h"
+
+static char *ataddr_string();
+static struct atNBPtuple *nbp_tuple_print();
+static struct atNBPtuple *nbp_name_print();
+static void atp_print();
+static void nbp_print();
+static void atp_bitmap_print();
+
+/*
+ * Print AppleTalk Datagram Delivery Protocol packets.
+ */
+void
+ddp_print(dp, length)
+       register struct atDDP *dp;
+       int length;
+{
+       if (length < ddpSize) {
+               (void)printf(" truncated-ddp %d", length);
+               return;
+       }
+       (void)printf("%s.%d > %s.%d:",
+                    ataddr_string(EXTRACT_SHORT(&dp->srcNet), dp->srcNode),
+                    dp->srcSkt,
+                    ataddr_string(EXTRACT_SHORT(&dp->dstNet), dp->dstNode),
+                    dp->dstSkt);
+
+       /* 'type' is the last field of 'dp' so we need the whole thing.
+          If we cannot determine the type, bail out.  (This last byte
+          happens to be *one* byte past the end of tcpdump's minimum
+          snapshot length.) */
+       if ((u_char *)(dp + 1) > snapend) {
+               printf(" [|atalk]");
+               return;
+       }
+
+       length -= ddpSize;
+       switch (dp->type) {
+
+       case ddpRTMP:
+               (void)printf(" at-rtmp %d", length);
+               break;
+       case ddpRTMPrequest:
+               (void)printf(" at-rtmpReq %d", length);
+               break;
+       case ddpNBP:
+               nbp_print((struct atNBP *)((u_char *)dp + ddpSize),
+                         length, dp);
+               break;
+       case ddpATP:
+               atp_print((struct atATP *)((u_char *)dp + ddpSize), length);
+               break;
+       case ddpECHO:
+               (void)printf(" at-echo %d", length);
+               break;
+       case ddpIP:
+               (void)printf(" at-IP %d", length);
+               break;
+       case ddpARP:
+               (void)printf(" at-ARP %d", length);
+               break;
+       case ddpKLAP:
+               (void)printf(" at-KLAP %d", length);
+               break;
+       default:
+               (void)printf(" at-#%d %d", length);
+               break;
+       }
+}
+
+static void
+atp_print(ap, length)
+       register struct atATP *ap;
+       int length;
+{
+       char c;
+       long data;
+
+       if ((u_char *)(ap + 1) > snapend) {
+               /* Just bail if we don't have the whole chunk. */
+               printf(" [|atalk]");
+               return;
+       }
+       length -= sizeof(*ap);
+       switch (ap->control & 0xc0) {
+
+       case atpReqCode:
+               (void)printf(" atp-req%s %d",
+                            ap->control & atpXO? " " : "*",
+                            EXTRACT_SHORT(&ap->transID));
+
+               atp_bitmap_print(ap->bitmap);
+
+               if (length != 0)
+                       (void)printf(" [len=%d]", length);
+
+               switch (ap->control & (atpEOM|atpSTS)) {
+               case atpEOM:
+                       (void)printf(" [EOM]");
+                       break;
+               case atpSTS:
+                       (void)printf(" [STS]");
+                       break;
+               case atpEOM|atpSTS:
+                       (void)printf(" [EOM,STS]");
+                       break;
+               }
+               break;
+
+       case atpRspCode:
+               (void)printf(" atp-resp%s%d:%d (%d)",
+                            ap->control & atpEOM? "*" : " ",
+                            EXTRACT_SHORT(&ap->transID), ap->bitmap, length);
+               switch (ap->control & (atpXO|atpSTS)) {
+               case atpXO:
+                       (void)printf(" [XO]");
+                       break;
+               case atpSTS:
+                       (void)printf(" [STS]");
+                       break;
+               case atpXO|atpSTS:
+                       (void)printf(" [XO,STS]");
+                       break;
+               }
+               break;
+
+       case atpRelCode:
+               (void)printf(" atp-rel  %d", EXTRACT_SHORT(&ap->transID));
+
+               atp_bitmap_print(ap->bitmap);
+
+               /* length should be zero */
+               if (length)
+                       (void)printf(" [len=%d]", length);
+
+               /* there shouldn't be any control flags */
+               if (ap->control & (atpXO|atpEOM|atpSTS)) {
+                       c = '[';
+                       if (ap->control & atpXO) {
+                               (void)printf("%cXO", c);
+                               c = ',';
+                       }
+                       if (ap->control & atpEOM) {
+                               (void)printf("%cEOM", c);
+                               c = ',';
+                       }
+                       if (ap->control & atpSTS) {
+                               (void)printf("%cSTS", c);
+                               c = ',';
+                       }
+                       (void)printf("]");
+               }
+               break;
+
+       default:
+               (void)printf(" atp-0x%x  %d (%d)", ap->control, 
+                            EXTRACT_SHORT(&ap->transID), length);
+               break;
+       }
+       data = EXTRACT_LONG(&ap->userData);
+       if (data != 0)
+               (void)printf(" 0x%x", data);
+}
+
+static void
+atp_bitmap_print(bm)
+       register u_char bm;
+{
+       register char c;
+       register int i;
+
+       /* 
+        * The '& 0xff' below is needed for compilers that want to sign
+        * extend a u_char, which is the case with the Ultrix compiler.
+        * (gcc is smart enough to eliminate it, at least on the Sparc).
+        */
+       if ((bm + 1) & (bm & 0xff)) {
+               c = '<';
+               for (i = 0; bm; ++i) {
+                       if (bm & 1) {
+                               (void)printf("%c%d", c, i);
+                               c = ',';
+                       }
+                       bm >>= 1;
+               }
+               (void)printf(">");
+       } else {
+               for (i = 0; bm; ++i)
+                       bm >>= 1;
+               if (i > 1)
+                       (void)printf("<0-%d>", i - 1);
+               else
+                       (void)printf("<0>");
+       }
+}
+
+static void
+nbp_print(np, length, dp)
+       register struct atNBP *np;
+       int length;
+       register struct atDDP *dp;
+{
+       register struct atNBPtuple *tp =
+                       (struct atNBPtuple *)((u_char *)np + nbpHeaderSize);
+       int i = length;
+       u_char *ep;
+
+       length -= nbpHeaderSize;
+       if (length < 8) {
+               /* must be room for at least one tuple */
+               (void)printf(" truncated-nbp %d", length + nbpHeaderSize);
+               return;
+       }
+       /* ep points to end of available data */
+       ep = snapend;
+       if ((u_char *)tp > ep) {
+               printf(" [|atalk]");
+               return;
+       }
+       switch (i = np->control & 0xf0) {
+
+       case nbpBrRq:
+       case nbpLkUp:
+               (void)printf(i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:",
+                            np->id);
+               if ((u_char *)(tp + 1) > ep) {
+                       printf(" [|atalk]");
+                       return;
+               }
+               (void)nbp_name_print(tp, ep);
+               /*
+                * look for anomalies: the spec says there can only
+                * be one tuple, the address must match the source
+                * address and the enumerator should be zero.
+                */
+               if ((np->control & 0xf) != 1)
+                       (void)printf(" [ntup=%d]", np->control & 0xf);
+               if (tp->enumerator)
+                       (void)printf(" [enum=%d]", tp->enumerator);
+               if (EXTRACT_SHORT(&tp->net) != EXTRACT_SHORT(&dp->srcNet) ||
+                   tp->node != dp->srcNode || tp->skt != dp->srcSkt)
+                       (void)printf(" [addr=%s.%d]",
+                                    ataddr_string(EXTRACT_SHORT(&tp->net), 
+                                                  tp->node), 
+                                    tp->skt);
+               break;
+
+       case nbpLkUpReply:
+               (void)printf(" nbp-reply %d:", np->id);
+
+               /* print each of the tuples in the reply */
+               for (i = np->control & 0xf; --i >= 0 && tp; )
+                       tp = nbp_tuple_print(tp, ep, dp);
+               break;
+
+       default:
+               (void)printf(" nbp-0x%x  %d (%d)", np->control, np->id,
+                               length);
+               break;
+       }
+}
+
+/* print a counted string */
+static char *
+print_cstring(cp, ep)
+       register char *cp;
+       register u_char *ep;
+{
+       register int length;
+
+       if (cp >= (char *)ep) {
+               (void)printf("[|atalk]");
+               return (0);
+       }
+       length = *cp++;
+
+       /* Spec says string can be at most 32 bytes long */
+       if (length < 0 || length > 32) {
+               (void)printf("[len=%d]", length);
+               return (0);
+       }
+       while (--length >= 0) {
+               if (cp >= (char *)ep) {
+                       (void)printf("[|atalk]");
+                       return (0);
+               }
+               putchar(*cp++);
+       }
+       return (cp);
+}
+
+static struct atNBPtuple *
+nbp_tuple_print(tp, ep, dp)
+       register struct atNBPtuple *tp;
+       register u_char *ep;
+       register struct atDDP *dp;
+{
+       register struct atNBPtuple *tpn;
+
+       if ((u_char *)(tp + 1) > ep) {
+               printf(" [|atalk]");
+               return 0;
+       }
+       tpn = nbp_name_print(tp, ep);
+
+       /* if the enumerator isn't 1, print it */
+       if (tp->enumerator != 1)
+               (void)printf("(%d)", tp->enumerator);
+
+       /* if the socket doesn't match the src socket, print it */
+       if (tp->skt != dp->srcSkt)
+               (void)printf(" %d", tp->skt);
+
+       /* if the address doesn't match the src address, it's an anomaly */
+       if (EXTRACT_SHORT(&tp->net) != EXTRACT_SHORT(&dp->srcNet) ||
+           tp->node != dp->srcNode)
+               (void)printf(" [addr=%s]",
+                            ataddr_string(EXTRACT_SHORT(&tp->net), tp->node));
+
+       return (tpn);
+}
+
+static struct atNBPtuple *
+nbp_name_print(tp, ep)
+       struct atNBPtuple *tp;
+       register u_char *ep;
+{
+       register char *cp = (char *)tp + nbpTupleSize;
+
+       putchar(' ');
+
+       /* Object */
+       putchar('"');
+       if (cp = print_cstring(cp, ep)) {
+               /* Type */
+               putchar(':');
+               if (cp = print_cstring(cp, ep)) {
+                       /* Zone */
+                       putchar('@');
+                       if (cp = print_cstring(cp, ep))
+                               putchar('"');
+               }
+       }
+       return ((struct atNBPtuple *)cp);
+}
+
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+       int addr;
+       char *name;
+       struct hnamemem *nxt;
+};
+
+static struct hnamemem hnametable[HASHNAMESIZE];
+
+static char *
+ataddr_string(atnet, athost)
+       u_short atnet;
+       u_char athost;
+{
+       register struct hnamemem *tp, *tp2;
+       register int i = (atnet << 8) | athost;
+       char nambuf[256];
+       static int first = 1;
+       FILE *fp;
+
+       /*
+        * if this is the first call, see if there's an AppleTalk
+        * number to name map file.
+        */
+       if (first && (first = 0, !nflag)
+           && (fp = fopen("/etc/atalk.names", "r"))) {
+               char line[256];
+               int i1, i2, i3;
+
+               while (fgets(line, sizeof(line), fp)) {
+                       if (line[0] == '\n' || line[0] == 0 || line[0] == '#')
+                               continue;
+                       if (sscanf(line, "%d.%d.%d %s", &i1, &i2, &i3,
+                                    nambuf) == 4)
+                               /* got a hostname. */
+                               i3 |= ((i1 << 8) | i2) << 8;
+                       else if (sscanf(line, "%d.%d %s", &i1, &i2,
+                                       nambuf) == 3)
+                               /* got a net name */
+                               i3 = (((i1 << 8) | i2) << 8) | 255;
+                       else
+                               continue;
+
+                       for (tp = &hnametable[i3 & (HASHNAMESIZE-1)];
+                            tp->nxt; tp = tp->nxt)
+                               ;
+                       tp->addr = i3;
+                       tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+                       i3 = strlen(nambuf) + 1;
+                       tp->name = strcpy(malloc((unsigned) i3), nambuf);
+               }
+               fclose(fp);
+       }
+
+       for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
+               if (tp->addr == i)
+                       return (tp->name);
+
+       /* didn't have the node name -- see if we've got the net name */
+       i |= 255;
+       for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt)
+               if (tp2->addr == i) {
+                       tp->addr = (atnet << 8) | athost;
+                       tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+                       (void)sprintf(nambuf, "%s.%d", tp2->name, athost);
+                       i = strlen(nambuf) + 1;
+                       tp->name = strcpy(malloc((unsigned) i), nambuf);
+                       return (tp->name);
+               }
+
+       tp->addr = (atnet << 8) | athost;
+       tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
+       if (athost != 255)
+               (void)sprintf(nambuf, "%d.%d.%d",
+                   atnet >> 8, atnet & 0xff, athost);
+       else
+               (void)sprintf(nambuf, "%d.%d", atnet >> 8, atnet & 0xff);
+       i = strlen(nambuf) + 1;
+       tp->name = strcpy(malloc((unsigned) i), nambuf);
+
+       return (tp->name);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-bootp.c b/usr/src/contrib/tcpdump/tcpdump/print-bootp.c
new file mode 100644 (file)
index 0000000..0641d82
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print bootp packets.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-bootp.c,v 1.17 91/11/14 22:21:34 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "bootp.h"
+
+void rfc1048_print();
+void cmu_print();
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(bp, length, sport, dport)
+       register struct bootp *bp;
+       int length;
+       u_short sport, dport;
+{
+       static char tstr[] = " [|bootp]";
+       static unsigned char vm_cmu[4] = VM_CMU;
+       static unsigned char vm_rfc1048[4] = VM_RFC1048;
+       u_char *ep;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+       /* Note funny sized packets */
+       if (length != sizeof(struct bootp))
+               (void)printf(" [len=%d]", length);
+
+       /* 'ep' points to the end of avaible data. */
+       ep = (u_char *)snapend;
+
+       switch (bp->bp_op) {
+
+       case BOOTREQUEST:
+               /* Usually, a request goes from a client to a server */
+               if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
+                       printf(" (request)");
+               break;
+
+       case BOOTREPLY:
+               /* Usually, a reply goes from a server to a client */
+               if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
+                       printf(" (reply)");
+               break;
+
+       default:
+               printf(" bootp-#%d", bp->bp_op);
+       }
+
+       NTOHL(bp->bp_xid);
+       NTOHS(bp->bp_secs);
+
+       /* The usual hardware address type is 1 (10Mb Ethernet) */
+       if (bp->bp_htype != 1)
+               printf(" htype-#%d", bp->bp_htype);
+
+       /* The usual length for 10Mb Ethernet address is 6 bytes */
+       if (bp->bp_htype != 1 || bp->bp_hlen != 6)
+               printf(" hlen:%d", bp->bp_hlen);
+
+       /* Only print interesting fields */
+       if (bp->bp_hops)
+               printf(" hops:%d", bp->bp_hops);
+       if (bp->bp_xid)
+               printf(" xid:0x%x", bp->bp_xid);
+       if (bp->bp_secs)
+               printf(" secs:%d", bp->bp_secs);
+
+       /* Client's ip address */
+       TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
+       if (bp->bp_ciaddr.s_addr)
+               printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
+
+       /* 'your' ip address (bootp client) */
+       TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
+       if (bp->bp_yiaddr.s_addr)
+               printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
+
+       /* Server's ip address */
+       TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
+       if (bp->bp_siaddr.s_addr)
+               printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
+
+       /* Gateway's ip address */
+       TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
+       if (bp->bp_giaddr.s_addr)
+               printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
+
+       /* Client's Ethernet address */
+       if (bp->bp_htype == 1 && bp->bp_hlen == 6) {
+               register struct ether_header *eh;
+               register char *e;
+
+               TCHECK(bp->bp_chaddr[0], 6);
+               eh = (struct ether_header *)packetp;
+               if (bp->bp_op == BOOTREQUEST)
+                       e = (char *)ESRC(eh);
+               else if (bp->bp_op == BOOTREPLY)
+                       e = (char *)EDST(eh);
+               else
+                       e = 0;
+               if (e == 0 || bcmp((char *)bp->bp_chaddr, e, 6) != 0)
+                       printf(" ether %s", etheraddr_string(bp->bp_chaddr));
+       }
+
+       TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname));
+       if (*bp->bp_sname) {
+               printf(" sname ");
+               if (printfn(bp->bp_sname, ep)) {
+                       fputs(tstr + 1, stdout);
+                       return;
+               }
+       }
+       TCHECK(bp->bp_file[0], sizeof(bp->bp_file));
+       if (*bp->bp_file) {
+               printf(" file ");
+               if (printfn(bp->bp_file, ep)) {
+                       fputs(tstr + 1, stdout);
+                       return;
+               }
+       }
+
+       /* Don't try to decode the vendor buffer unless we're verbose */
+       if (vflag <= 0)
+               return;
+
+       TCHECK(bp->bp_vend[0], sizeof(bp->bp_vend));
+       printf(" vend");
+       if (bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_long)) == 0)
+               rfc1048_print(bp->bp_vend, sizeof(bp->bp_vend));
+       else if (bcmp(bp->bp_vend, vm_cmu, sizeof(u_long)) == 0)
+               cmu_print(bp->bp_vend, sizeof(bp->bp_vend));
+       else {
+               u_long ul;
+
+               bcopy((char *)bp->bp_vend, (char *)&ul, sizeof(ul));
+               printf("-#0x%x", ul);
+       }
+
+       return;
+trunc:
+       fputs(tstr, stdout);
+#undef TCHECK
+}
+
+void
+rfc1048_print(bp, length)
+       register u_char *bp;
+       int length;
+{
+       u_char tag;
+       u_char *ep;
+       register int i;
+       u_long ul;
+
+       printf("-rfc1048");
+
+       /* Step over magic cookie */
+       bp += sizeof(long);
+
+       /* Setup end pointer */
+       ep = bp + length;
+
+       while (bp < ep) {
+               tag = *bp++;
+               i = *bp++;
+               switch (tag) {
+
+               case TAG_PAD:
+                       /* no-op */
+                       break;
+
+               case TAG_SUBNET_MASK:
+                       ul = 0;
+                       bcopy((char *)bp, (char *)&ul, i);
+                       printf(" SM:%s", ipaddr_string(&ul));
+                       break;
+
+               case TAG_TIME_SERVER:
+                       ul = 0;
+                       bcopy((char *)bp, (char *)&ul, i);
+                       printf(" TS:%s", ipaddr_string(&ul));
+                       break;
+
+               case TAG_GATEWAY:
+                       ul = 0;
+                       bcopy((char *)bp, (char *)&ul, i);
+                       printf(" G:%s", ipaddr_string(&ul));
+                       break;
+
+               case TAG_TIME_OFFSET:
+               case TAG_NAME_SERVER:
+               case TAG_DOMAIN_SERVER:
+               case TAG_LOG_SERVER:
+               case TAG_COOKIE_SERVER:
+               case TAG_LPR_SERVER:
+               case TAG_IMPRESS_SERVER:
+               case TAG_RLP_SERVER:
+               case TAG_HOSTNAME:
+               case TAG_BOOTSIZE:
+                       printf(" tag-#%d", tag);
+                       if (i == sizeof(long)) {
+                               bcopy((char *)bp, (char *)&ul, sizeof(long));
+                               printf(":0x%x", ul);
+                       } else
+                               printf(":?");
+                       break;
+
+               case TAG_END:
+                       return;
+
+               default:
+                       printf("[tag-#%d]", tag);
+                       return;
+               }
+       }
+}
+
+void
+cmu_print(bp, length)
+       register u_char *bp;
+       int length;
+{
+       /* XXX not really implemented */
+       printf("-cmu [...]");
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-domain.c b/usr/src/contrib/tcpdump/tcpdump/print-domain.c
new file mode 100644 (file)
index 0000000..04cf5aa
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-domain.c,v 1.16 92/05/25 14:28:59 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <arpa/nameser.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static char *ns_ops[] = {
+       "", " inv_q", " stat", " op3", " op4", " op5", " op6", " op7",
+       " op8", " updataA", " updateD", " updateDA",
+       " updateM", " updateMA", " zoneInit", " zoneRef",
+};
+
+static char *ns_resp[] = {
+       "", " FormErr", " ServFail", " NXDomain",
+       " NotImp", " Refused", " Resp6", " Resp7",
+       " Resp8", " Resp9", " Resp10", " Resp11",
+       " Resp12", " Resp13", " Resp14", " NoChange",
+};
+
+
+/* skip over a domain name */
+static u_char *
+ns_nskip(cp)
+       register u_char *cp;
+{
+       register u_char i;
+
+       if (((i = *cp++) & 0xc0) == 0xc0)
+               return (cp + 1);
+       while (i) {
+               cp += i;
+               i = *cp++;
+       }
+       return (cp);
+}
+
+/* print a domain name */
+static void
+ns_nprint(cp, bp, ep)
+       register u_char *cp;
+       register u_char *bp;
+       register u_char *ep;
+{
+       register u_int i;
+
+       putchar(' ');
+       if (i = *cp++)
+               while (i && cp < ep) {
+                       if ((i & 0xc0) == 0xc0) {
+                               cp = bp + (((i << 8) | *cp) & 0x3fff);
+                               i = *cp++;
+                               continue;
+                       }
+                       do {
+                               putchar(*cp++);
+                       } while (--i);
+                       putchar('.');
+                       i = *cp++;
+               }
+       else
+               putchar('.');
+}
+
+
+/* print a query */
+static void
+ns_qprint(cp, bp, ep)
+       register u_char *cp;
+       register u_char *bp;
+       register u_char *ep;
+{
+       u_char *np = cp;
+       register u_int i;
+
+       cp = ns_nskip(cp);
+
+       if (cp + 4 > ep)
+               return;
+
+       /* print the qtype and qclass (if it's not IN) */
+       i = *cp++ << 8;
+       switch (i |= *cp++) {
+       case T_A:       printf(" A"); break;
+       case T_NS:      printf(" NS"); break;
+       case T_MD:      printf(" MD"); break;
+       case T_MF:      printf(" MF"); break;
+       case T_CNAME:   printf(" CNAME"); break;
+       case T_SOA:     printf(" SOA"); break;
+       case T_MB:      printf(" MB"); break;
+       case T_MG:      printf(" MG"); break;
+       case T_MR:      printf(" MR"); break;
+       case T_NULL:    printf(" NULL"); break;
+       case T_WKS:     printf(" WKS"); break;
+       case T_PTR:     printf(" PTR"); break;
+       case T_HINFO:   printf(" HINFO"); break;
+       case T_MINFO:   printf(" MINFO"); break;
+       case T_MX:      printf(" MX"); break;
+       case T_UINFO:   printf(" UINFO"); break;
+       case T_UID:     printf(" UID"); break;
+       case T_GID:     printf(" GID"); break;
+#ifdef T_UNSPEC
+       case T_UNSPEC:  printf(" UNSPEC"); break;
+#endif
+       case T_AXFR:    printf(" AXFR"); break;
+       case T_MAILB:   printf(" MAILB"); break;
+       case T_MAILA:   printf(" MAILA"); break;
+       case T_ANY:     printf(" ANY"); break;
+       default:        printf(" Type%d", i); break;
+       }
+       i = *cp++ << 8;
+       if ((i |= *cp++) != C_IN)
+               if (i == C_ANY)
+                       printf("(c_any)");
+               else
+                       printf("(Class %d)", i);
+
+       putchar('?');
+       ns_nprint(np, bp, ep);
+}
+
+
+/* print a reply */
+static void
+ns_rprint(cp, bp, ep)
+       register u_char *cp;
+       register u_char *bp;
+       register u_char *ep;
+{
+       register u_int i;
+       u_short typ;
+
+       cp = ns_nskip(cp);
+
+       if (cp + 10 > ep)
+               return;
+
+       /* print the type/qtype and class (if it's not IN) */
+       typ = *cp++ << 8;
+       typ |= *cp++;
+       i = *cp++ << 8;
+       if ((i |= *cp++) != C_IN)
+               if (i == C_ANY)
+                       printf("(c_any)");
+               else
+                       printf("(Class %d)", i);
+
+       /* ignore ttl & len */
+       cp += 6;
+       switch (typ) {
+       case T_A:       printf(" A %s", ipaddr_string(cp)); break;
+       case T_NS:      printf(" NS"); ns_nprint(cp, bp, ep); break;
+       case T_MD:      printf(" MD"); break;
+       case T_MF:      printf(" MF"); break;
+       case T_CNAME:   printf(" CNAME"); ns_nprint(cp, bp, ep); break;
+       case T_SOA:     printf(" SOA"); break;
+       case T_MB:      printf(" MB"); break;
+       case T_MG:      printf(" MG"); break;
+       case T_MR:      printf(" MR"); break;
+       case T_NULL:    printf(" NULL"); break;
+       case T_WKS:     printf(" WKS"); break;
+       case T_PTR:     printf(" PTR"); ns_nprint(cp, bp, ep); break;
+       case T_HINFO:   printf(" HINFO"); break;
+       case T_MINFO:   printf(" MINFO"); break;
+       case T_MX:      printf(" MX"); ns_nprint(cp+2, bp, ep);
+#ifndef TCPDUMP_ALIGN
+                       printf(" %d", *(short *)cp);
+#else
+                       {
+                           u_short x = *cp | cp[1] << 8; 
+                           printf(" %d", ntohs(x));
+                       }
+#endif
+                       break;
+       case T_UINFO:   printf(" UINFO"); break;
+       case T_UID:     printf(" UID"); break;
+       case T_GID:     printf(" GID"); break;
+#ifdef T_UNSPEC
+       case T_UNSPEC:  printf(" UNSPEC"); break;
+#endif
+       case T_AXFR:    printf(" AXFR"); break;
+       case T_MAILB:   printf(" MAILB"); break;
+       case T_MAILA:   printf(" MAILA"); break;
+       case T_ANY:     printf(" ANY"); break;
+       default:        printf(" Type%d", typ); break;
+       }
+}
+
+void
+ns_print(np, length)
+       register HEADER *np;
+       int length;
+{
+       u_char *ep = (u_char *)snapend;
+
+       /* get the byte-order right */
+       NTOHS(np->id);
+       NTOHS(np->qdcount);
+       NTOHS(np->ancount);
+       NTOHS(np->nscount);
+       NTOHS(np->arcount);
+
+       if (np->qr) {
+               /* this is a response */
+               printf(" %d%s%s%s%s%s",
+                       np->id,
+                       ns_ops[np->opcode],
+                       ns_resp[np->rcode],
+                       np->aa? "*" : "",
+                       np->ra? "" : "-",
+                       np->tc? "|" : "");
+               if (np->qdcount != 1)
+                       printf(" [%dq]", np->qdcount);
+               printf(" %d/%d/%d", np->ancount, np->nscount, np->arcount);
+               if (np->ancount)
+                       ns_rprint(ns_nskip((u_char *)(np + 1)) + 4,
+                                 (u_char *)np, ep);
+       }
+       else {
+               /* this is a request */
+               printf(" %d%s%s",
+                       np->id,
+                       ns_ops[np->opcode],
+                       np->rd? "+" : "");
+
+               /* any weirdness? */
+               if (*(((u_short *)np)+1) & htons(0x6ff))
+                       printf(" [b2&3=0x%x]", ntohs(*(((u_short *)np)+1)));
+
+               if (np->opcode == IQUERY) {
+                       if (np->qdcount)
+                               printf(" [%dq]", np->qdcount);
+                       if (np->ancount != 1)
+                               printf(" [%da]", np->ancount);
+               }
+               else {
+                       if (np->ancount)
+                               printf(" [%da]", np->ancount);
+                       if (np->qdcount != 1)
+                               printf(" [%dq]", np->qdcount);
+               }
+               if (np->nscount)
+                       printf(" [%dn]", np->nscount);
+               if (np->arcount)
+                       printf(" [%dau]", np->arcount);
+
+               ns_qprint((u_char *)(np + 1), (u_char *)np, ep);
+       }
+       printf(" (%d)", length);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-egp.c b/usr/src/contrib/tcpdump/tcpdump/print-egp.c
new file mode 100644 (file)
index 0000000..a88a683
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Lawrence Berkeley Laboratory,
+ * Berkeley, CA.  The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU).
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netdb.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+struct egp_packet {
+       u_char  egp_version;
+#define        EGP_VERSION     2
+       u_char  egp_type;
+#define  EGPT_ACQUIRE  3
+#define  EGPT_REACH    5
+#define  EGPT_POLL     2
+#define  EGPT_UPDATE   1
+#define  EGPT_ERROR    8
+       u_char  egp_code;
+#define  EGPC_REQUEST  0
+#define  EGPC_CONFIRM  1
+#define  EGPC_REFUSE   2
+#define  EGPC_CEASE    3
+#define  EGPC_CEASEACK 4
+#define  EGPC_HELLO    0
+#define  EGPC_HEARDU   1
+       u_char  egp_status;
+#define  EGPS_UNSPEC   0
+#define  EGPS_ACTIVE   1
+#define  EGPS_PASSIVE  2
+#define  EGPS_NORES    3
+#define  EGPS_ADMIN    4
+#define  EGPS_GODOWN   5
+#define  EGPS_PARAM    6
+#define  EGPS_PROTO    7
+#define  EGPS_INDET    0
+#define  EGPS_UP       1
+#define  EGPS_DOWN     2
+#define  EGPS_UNSOL    0x80
+       u_short  egp_checksum;
+       u_short  egp_as;
+       u_short  egp_sequence;
+       union {
+               u_short  egpu_hello;
+               u_char egpu_gws[2];
+               u_short  egpu_reason;
+#define  EGPR_UNSPEC   0
+#define  EGPR_BADHEAD  1
+#define  EGPR_BADDATA  2
+#define  EGPR_NOREACH  3
+#define  EGPR_XSPOLL   4
+#define  EGPR_NORESP   5
+#define  EGPR_UVERSION 6
+       } egp_handg;
+#define  egp_hello  egp_handg.egpu_hello
+#define  egp_intgw  egp_handg.egpu_gws[0]
+#define  egp_extgw  egp_handg.egpu_gws[1]
+#define  egp_reason  egp_handg.egpu_reason
+       union {
+               u_short  egpu_poll;
+               u_long egpu_sourcenet;
+       } egp_pands;
+#define  egp_poll  egp_pands.egpu_poll
+#define  egp_sourcenet  egp_pands.egpu_sourcenet
+};
+
+char *egp_acquire_codes[] = {
+       "request",
+       "confirm",
+       "refuse",
+       "cease",
+       "cease_ack"
+};
+
+char *egp_acquire_status[] = {
+       "unspecified",
+       "active_mode",
+       "passive_mode",
+       "insufficient_resources",
+       "administratively_prohibited",
+       "going_down",
+       "parameter_violation",
+       "protocol_violation"
+};
+
+char *egp_reach_codes[] = {
+       "hello",
+       "i-h-u"
+};
+
+char *egp_status_updown[] = {
+       "indeterminate",
+       "up",
+       "down"
+};
+
+char *egp_reasons[] = {
+       "unspecified",
+       "bad_EGP_header_format",
+       "bad_EGP_data_field_format",
+       "reachability_info_unavailable",
+       "excessive_polling_rate",
+       "no_response",
+       "unsupported_version"
+};
+
+static void
+egpnrprint(egp, length)
+       register struct egp_packet *egp;
+       register int length;
+{
+       register u_char *cp, *ep;
+#define TCHECK(n) if (cp > ep - n) goto trunc
+       register u_long addr;
+       register u_long net;
+       register int netlen;
+       int gateways, distances, networks;
+       int t_gateways;
+       char *comma;
+
+       addr = egp->egp_sourcenet;
+       if (IN_CLASSA(addr)) {
+               net = addr & IN_CLASSA_NET;
+               netlen = 1;
+       } else if (IN_CLASSB(addr)) {
+               net = addr & IN_CLASSB_NET;
+               netlen = 2;
+       } else if (IN_CLASSC(addr)) {
+               net = addr & IN_CLASSC_NET;
+               netlen = 3;
+       } else {
+               net = 0;
+               netlen = 0;
+       }
+       cp = (u_char *)(egp + 1);
+       ep = snapend;
+
+       t_gateways = egp->egp_intgw + egp->egp_extgw;
+       for (gateways = 0; gateways < t_gateways; ++gateways) {
+               /* Pickup host part of gateway address */
+               addr = 0;
+               TCHECK(4 - netlen);
+               switch (netlen) {
+
+               case 1:
+                       addr = *cp++;
+                       /* fall through */
+               case 2:
+                       addr = (addr << 8) | *cp++;
+                       /* fall through */
+               case 3:
+                       addr = (addr << 8) | *cp++;
+               }
+               addr |= net;
+               TCHECK(1);
+               distances = *cp++;
+               printf(" %s %s ",
+                      gateways < egp->egp_intgw ? "int" : "ext", 
+                      intoa(addr));
+               
+               comma = "";
+               putchar('(');
+               while (--distances >= 0) {
+                       TCHECK(2);
+                       printf("%sd%d:", comma, (int)*cp++);
+                       comma = ", ";
+                       networks = *cp++;
+                       while (--networks >= 0) {
+                               /* Pickup network number */
+                               TCHECK(1);
+                               addr = (u_long)*cp++ << 24;
+                               if (IN_CLASSB(addr)) {
+                                       TCHECK(1);
+                                       addr |= (u_long)*cp++ << 16;
+                               } else if (!IN_CLASSA(addr)) {
+                                       TCHECK(2);
+                                       addr |= (u_long)*cp++ << 16;
+                                       addr |= (u_long)*cp++ << 8;
+                               }
+                               printf(" %s", intoa(addr));
+                       }
+               }
+               putchar(')');
+       }
+       return;
+trunc:
+       fputs("[|]", stdout);
+}
+
+void
+egp_print(egp, length, ip)
+       register struct egp_packet *egp;
+       register int length;
+       register struct ip *ip;
+{
+       register int status;
+       register int code;
+       register int type;
+       
+        (void)printf("%s > %s: egp: ",
+                    ipaddr_string(&ip->ip_src),
+                    ipaddr_string(&ip->ip_dst));
+
+       if (egp->egp_version != EGP_VERSION) {
+               printf("[version %d]", egp->egp_version);
+               return;
+       }
+       printf("as:%d seq:%d", ntohs(egp->egp_as), ntohs(egp->egp_sequence));
+       
+       type = egp->egp_type;
+       code = egp->egp_code;
+       status = egp->egp_status;
+
+       switch (type) {
+       case EGPT_ACQUIRE:
+               printf(" acquire");
+               switch (code) {
+               case EGPC_REQUEST:
+               case EGPC_CONFIRM:
+                       printf(" %s", egp_acquire_codes[code]);
+                       switch (status) {
+                       case EGPS_UNSPEC:
+                       case EGPS_ACTIVE:
+                       case EGPS_PASSIVE:
+                               printf(" %s", egp_acquire_status[status]);
+                               break;
+                               
+                       default:
+                               printf(" [status %d]", status);
+                               break;
+                       }
+                       printf(" hello:%d poll:%d",
+                              ntohs(egp->egp_hello),
+                              ntohs(egp->egp_poll));
+                       break;
+                       
+               case EGPC_REFUSE:
+               case EGPC_CEASE:
+               case EGPC_CEASEACK:
+                       printf(" %s", egp_acquire_codes[code]);
+                       switch (status ) {
+                       case EGPS_UNSPEC:
+                       case EGPS_NORES:
+                       case EGPS_ADMIN:
+                       case EGPS_GODOWN:
+                       case EGPS_PARAM:
+                       case EGPS_PROTO:
+                               printf(" %s", egp_acquire_status[status]);
+                               break;
+                               
+                       default:
+                               printf("[status %d], status");
+                               break;
+                       }
+                       break;
+                       
+               default:
+                       printf("[code %d]", code);
+                       break;
+               }
+               break;
+               
+       case EGPT_REACH:
+               switch (code) {
+
+               case EGPC_HELLO:
+               case EGPC_HEARDU:
+                       printf(" %s", egp_reach_codes[code]);
+                       if (status <= EGPS_DOWN)
+                               printf(" state:%s", egp_status_updown[status]);
+                       else
+                               printf(" [status %d], status");
+                       break;
+                       
+               default:
+                       printf("[reach code %d], code");
+                       break;
+               }
+               break;
+               
+       case EGPT_POLL:
+               printf(" poll");
+               if (egp->egp_status <= EGPS_DOWN)
+                       printf(" state:%s", egp_status_updown[status]);
+               else
+                       printf(" [status %d]", status);
+               printf(" net:%s", intoa(egp->egp_sourcenet));
+               break;
+               
+       case EGPT_UPDATE:
+               printf(" update");
+               if (status & EGPS_UNSOL) {
+                       status &= ~EGPS_UNSOL;
+                       printf(" unsolicitied");
+               }
+               if (status <= EGPS_DOWN)
+                       printf(" state:%s", egp_status_updown[status]);
+               else
+                       printf(" [status %d]", status);
+               printf(" %s int %d ext %d",
+                      intoa(egp->egp_sourcenet),
+                      egp->egp_intgw,
+                      egp->egp_extgw);
+               if (vflag)
+                       egpnrprint(egp, length);
+               break;
+               
+       case EGPT_ERROR:
+               printf(" error");
+               if (status <= EGPS_DOWN)
+                       printf(" state:%s", egp_status_updown[status]);
+               else
+                       printf(" [status]", status);
+
+               if (ntohs(egp->egp_reason) <= EGPR_UVERSION)
+                       printf(" %s", egp_reasons[ntohs(egp->egp_reason)]);
+               else
+                       printf(" [reason]", ntohs(egp->egp_reason));
+               break;
+               
+       default:
+               printf("[type %d]", type);
+               break;
+       }
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-ether.c b/usr/src/contrib/tcpdump/tcpdump/print-ether.c
new file mode 100644 (file)
index 0000000..2d01c17
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-ether.c,v 1.22 91/10/07 20:18:28 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+u_char *packetp;
+u_char *snapend;
+
+static inline void
+ether_print(ep, length)
+       register struct ether_header *ep;
+       int length;
+{
+       if (qflag)
+               (void)printf("%s %s %d: ",
+                            etheraddr_string(ESRC(ep)),
+                            etheraddr_string(EDST(ep)),
+                            length);
+       else
+               (void)printf("%s %s %s %d: ",
+                            etheraddr_string(ESRC(ep)),
+                            etheraddr_string(EDST(ep)),
+                            etherproto_string(ep->ether_type), 
+                            length);
+}
+
+/*
+ * This is the top level routine of the printer.  'p' is the points
+ * to the ether header of the packet, 'tvp' is the timestamp, 
+ * 'length' is the length of the packet off the wire, and 'caplen'
+ * is the number of bytes actually captured.
+ */
+void
+ether_if_print(p, tvp, length, caplen)
+       u_char *p;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct ether_header *ep;
+       register int i;
+
+       ts_print(tvp);
+
+       if (caplen < sizeof(struct ether_header)) {
+               printf("[|ether]");
+               goto out;
+       }
+
+       if (eflag)
+               ether_print((struct ether_header *)p, length);
+
+       /*
+        * Some printers want to get back at the ethernet addresses,
+        * and/or check that they're not walking off the end of the packet.
+        * Rather than pass them all the way down, we set these globals.
+        */
+       packetp = p;
+       snapend = p + caplen;
+       
+       length -= sizeof(struct ether_header);
+       ep = (struct ether_header *)p;
+       p += sizeof(struct ether_header);
+       switch (ntohs(ep->ether_type)) {
+
+       case ETHERTYPE_IP:
+               ip_print((struct ip *)p, length);
+               break;
+
+       case ETHERTYPE_ARP:
+       case ETHERTYPE_REVARP:
+               arp_print((struct ether_arp *)p, length, caplen - sizeof(*ep));
+               break;
+
+       default:
+               if (!eflag)
+                       ether_print(ep, length);
+               if (!xflag && !qflag)
+                       default_print((u_short *)p, caplen - sizeof(*ep));
+               break;
+       }
+       if (xflag)
+               default_print((u_short *)p, caplen - sizeof(*ep));
+ out:
+       putchar('\n');
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-fddi.c b/usr/src/contrib/tcpdump/tcpdump/print-fddi.c
new file mode 100644 (file)
index 0000000..7783112
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static  char rcsid[] =
+       "@(#)$Header: print-fddi.c,v 1.4 92/02/03 16:04:02 van Exp $ (LBL)";
+#endif
+
+#ifdef FDDI
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/*
+ * NOTE:  This is a very preliminary hack for FDDI support.
+ * There are all sorts of wired in constants & nothing (yet)
+ * to print SMT packets as anything other than hex dumps.
+ * Most of the necessary changes are waiting on my redoing
+ * the "header" that a kernel fddi driver supplies to bpf:  I
+ * want it to look like one byte of 'direction' (0 or 1
+ * depending on whether the packet was inbound or outbound),
+ * two bytes of system/driver dependent data (anything an
+ * implementor thinks would be useful to filter on and/or
+ * save per-packet, then the real 21-byte FDDI header.
+ * Steve McCanne & I have also talked about adding the
+ * 'direction' byte to all bpf headers (e.g., in the two
+ * bytes of padding on an ethernet header).  It's not clear
+ * we could do this in a backwards compatible way & we hate
+ * the idea of an incompatible bpf change.  Discussions are
+ * proceeding.
+ *
+ * Also, to really support FDDI (and better support 802.2
+ * over ethernet) we really need to re-think the rather simple
+ * minded assumptions about fixed length & fixed format link
+ * level headers made in gencode.c.  One day...
+ *
+ *  - vj
+ */
+
+/* XXX This goes somewhere else. */
+#define FDDI_HDRLEN 21
+
+static u_char fddi_bit_swap[] = {
+       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+       0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+       0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+       0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+       0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+       0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+       0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+       0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+       0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+       0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+       0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+       0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+       0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+       0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+       0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+       0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+       0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+       0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+       0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+       0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+       0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+       0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+       0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+       0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+       0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+       0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+       0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+       0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+       0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+       0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+static inline void
+fddi_print(p, length)
+       u_char *p;
+       int length;
+{
+       u_char fsrc[6], fdst[6];
+       register char *srcname, *dstname;
+       register int i;
+
+       /*
+        * bit-swap the fddi addresses (isn't the IEEE standards
+        * process wonderful!) then convert them to names. 
+        */
+       
+       for (i = 0; i < sizeof(fdst); ++i)
+               fdst[i] = fddi_bit_swap[p[i+1]];
+       for (i = 0; i < sizeof(fsrc); ++i)
+               fsrc[i] = fddi_bit_swap[p[i+7]];
+       dstname = etheraddr_string(fdst);
+       srcname = etheraddr_string(fsrc);
+
+       if (vflag)
+               printf("%s %s %02x %02x %02x %02x %02x%02x%02x %s %d: ",
+                      dstname, srcname,
+                      p[0],
+                      p[13], p[14], p[15],
+                      p[16], p[17], p[18],
+                      etherproto_string((p[19] << 8) | p[20]),
+                      length);
+       else if (qflag)
+               printf("%s %s %d: ", dstname, srcname, length);
+       else
+               printf("%s %s %02x %s %d: ",
+                      dstname, srcname,
+                      p[0],
+                      etherproto_string((p[19] << 8) | p[20]),
+                      length);
+}
+
+void
+fddi_if_print(p, tvp, length, caplen)
+       u_char *p;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct ip *ip;
+       u_short type;
+
+       ts_print(tvp);
+
+       if (caplen < FDDI_HDRLEN) {
+               printf("[|fddi]");
+               goto out;
+       }
+
+       /*
+        * Some printers want to get back at the link level addresses,
+        * and/or check that they're not walking off the end of the packet.
+        * Rather than pass them all the way down, we set these globals.
+        */
+       packetp = (u_char *)p;
+       snapend = (u_char *)p + caplen;
+
+       /*
+        * If the frame is not an LLC frame or is not an LLC/UI frame
+        * or doesn't have SNAP as a dest NSAP, use the default printer.
+        * (XXX - should interpret SMT packets here.)
+        */
+       if ((p[0] & 0xf8) != 0x50)
+               /* not LLC frame -- use default printer */
+               type = 0;
+       else if ((p[15] &~ 0x10) != 0x03)
+               /* not UI frame -- use default printer */
+               type = 0;
+       else if (p[13] != 170)
+               /* DSAP not SNAP -- use default printer */
+               type = 0;
+       else
+               type = (p[19] << 8) | p[20];
+       if (eflag)
+               fddi_print(p, length);
+
+       length -= FDDI_HDRLEN;
+       p += FDDI_HDRLEN;
+
+       switch (ntohs(type)) {
+
+       case ETHERTYPE_IP:
+               ip_print((struct ip *)p, length);
+               break;
+
+       case ETHERTYPE_ARP:
+       case ETHERTYPE_REVARP:
+               arp_print((struct ether_arp *)p, length, caplen - FDDI_HDRLEN);
+               break;
+
+       default:
+               if (!eflag)
+                       fddi_print(p, length);
+               if (!xflag && !qflag)
+                       default_print((u_short *)p, caplen - FDDI_HDRLEN);
+               break;
+       }
+       if (xflag)
+               default_print((u_short *)p, caplen - sizeof(FDDI_HDRLEN));
+out:
+       putchar('\n');
+}
+#else
+#include <stdio.h>
+void
+fddi_if_print()
+{
+       void error();
+
+       error("not configured for fddi");
+       /* NOTREACHED */
+}
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-icmp.c b/usr/src/contrib/tcpdump/tcpdump/print-icmp.c
new file mode 100644 (file)
index 0000000..928d866
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-icmp.c,v 1.11 91/03/27 17:42:58 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <netinet/ip_icmp.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+icmp_print(dp, ip)
+       register struct icmp *dp;
+       register struct ip *ip;
+{
+       char buf[256];
+       register char *str = buf;
+       register struct ip *oip;
+       register struct udphdr *ouh;
+       register int hlen;
+       u_char *ep;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+       /* 'ep' points to the end of avaible data. */
+       ep = (u_char *)snapend;
+
+        (void)printf("%s > %s: ",
+               ipaddr_string(&ip->ip_src),
+               ipaddr_string(&ip->ip_dst));
+       strcpy(str, "[?]");
+
+       TCHECK(dp->icmp_code, sizeof(dp->icmp_code));
+       switch (dp->icmp_type) {
+       case ICMP_ECHOREPLY:
+               str = "echo reply";
+               break;
+       case ICMP_UNREACH:
+               TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+               switch (dp->icmp_code) {
+               case ICMP_UNREACH_NET:
+                       (void)sprintf(buf, "net %s unreachable",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst));
+                       break;
+               case ICMP_UNREACH_HOST:
+                       (void)sprintf(buf, "host %s unreachable",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst));
+                       break;
+               case ICMP_UNREACH_PROTOCOL:
+                       TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p));
+                       (void)sprintf(buf, "%s protocol %d unreachable",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst),
+                                      dp->icmp_ip.ip_p);
+                       break;
+               case ICMP_UNREACH_PORT:
+                       TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p));
+                       oip = &dp->icmp_ip;
+                       hlen = oip->ip_hl * 4;
+                       ouh = (struct udphdr *)(((u_char *)oip) + hlen);
+                       NTOHS(ouh->uh_dport);
+                       switch (oip->ip_p) {
+                       case IPPROTO_TCP:
+                               (void)sprintf(buf,
+                                       "%s tcp port %s unreachable",
+                                       ipaddr_string(&oip->ip_dst),
+                                       tcpport_string(ouh->uh_dport));
+                               break;
+                       case IPPROTO_UDP:
+                               (void)sprintf(buf,
+                                       "%s udp port %s unreachable",
+                                       ipaddr_string(&oip->ip_dst),
+                                       udpport_string(ouh->uh_dport));
+                               break;
+                       default:
+                               (void)sprintf(buf,
+                                       "%s protocol %d port %d unreachable",
+                                       ipaddr_string(&oip->ip_dst),
+                                       oip->ip_p, ouh->uh_dport);
+                               break;
+                       }
+                       break;
+               case ICMP_UNREACH_NEEDFRAG:
+                       (void)sprintf(buf, "%s unreachable - need to frag",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst));
+                       break;
+               case ICMP_UNREACH_SRCFAIL:
+                       (void)sprintf(buf,
+                               "%s unreachable - source route failed",
+                               ipaddr_string(&dp->icmp_ip.ip_dst));
+                       break;
+               }
+               break;
+       case ICMP_SOURCEQUENCH:
+               str = "source quench";
+               break;
+       case ICMP_REDIRECT:
+               TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+               switch (dp->icmp_code) {
+               case ICMP_REDIRECT_NET:
+                       (void)sprintf(buf, "redirect %s to net %s",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst),
+                                      ipaddr_string(&dp->icmp_gwaddr));
+                       break;
+               case ICMP_REDIRECT_HOST:
+                       (void)sprintf(buf, "redirect %s to host %s",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst),
+                                      ipaddr_string(&dp->icmp_gwaddr));
+                       break;
+               case ICMP_REDIRECT_TOSNET:
+                       (void)sprintf(buf, "redirect-tos %s to net %s",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst),
+                                      ipaddr_string(&dp->icmp_gwaddr));
+                       break;
+               case ICMP_REDIRECT_TOSHOST:
+                       (void)sprintf(buf, "redirect-tos %s to host %s",
+                                      ipaddr_string(&dp->icmp_ip.ip_dst),
+                                      ipaddr_string(&dp->icmp_gwaddr));
+                       break;
+               }
+               break;
+       case ICMP_ECHO:
+               str = "echo request";
+               break;
+       case ICMP_TIMXCEED:
+               TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst));
+               switch (dp->icmp_code) {
+               case ICMP_TIMXCEED_INTRANS:
+                       str = "time exceeded in-transit";
+                       break;
+               case ICMP_TIMXCEED_REASS:
+                       str = "ip reassembly time exceeded";
+                       break;
+               }
+               break;
+       case ICMP_PARAMPROB:
+               if (dp->icmp_code)
+                       (void)sprintf(buf, "parameter problem - code %d",
+                                       dp->icmp_code);
+               else {
+                       TCHECK(dp->icmp_pptr, sizeof(dp->icmp_pptr));
+                       (void)sprintf(buf, "parameter problem - octet %d",
+                                       dp->icmp_pptr);
+               }
+               break;
+       case ICMP_TSTAMP:
+               str = "time stamp request";
+               break;
+       case ICMP_TSTAMPREPLY:
+               str = "time stamp reply";
+               break;
+       case ICMP_IREQ:
+               str = "information request";
+               break;
+       case ICMP_IREQREPLY:
+               str = "information reply";
+               break;
+       case ICMP_MASKREQ:
+               str = "address mask request";
+               break;
+       case ICMP_MASKREPLY:
+               TCHECK(dp->icmp_mask, sizeof(dp->icmp_mask));
+               (void)sprintf(buf, "address mask is 0x%08x", dp->icmp_mask);
+               break;
+       }
+        (void)printf("icmp: %s", str);
+       return;
+trunc:
+       fputs("[|icmp]", stdout);
+#undef TCHECK
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-ip.c b/usr/src/contrib/tcpdump/tcpdump/print-ip.c
new file mode 100644 (file)
index 0000000..8716a01
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-ip.c,v 1.28 92/05/25 14:29:02 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+igmp_print(cp, len, ip)
+       register u_char *cp;
+       register int len;
+       register struct ip *ip;
+{
+       register u_char *ep = (u_char *)snapend;
+
+        (void)printf("%s > %s: ",
+               ipaddr_string(&ip->ip_src),
+               ipaddr_string(&ip->ip_dst));
+
+       if (cp + 7 > ep) {
+               (void)printf("[|igmp]");
+               return;
+       }
+       switch (cp[0] & 0xf) {
+       case 1:
+               (void)printf("igmp query");
+               if (*(int *)&cp[4])
+                       (void)printf(" [gaddr %s]", ipaddr_string(&cp[4]));
+               if (len != 8)
+                       (void)printf(" [len %d]", len);
+               break;
+       case 2:
+               (void)printf("igmp report %s", ipaddr_string(&cp[4]));
+               if (len != 8)
+                       (void)printf(" [len %d]", len);
+               break;
+       case 3:
+               (void)printf("igmp dvmrp", ipaddr_string(&cp[4]));
+               if (len < 8)
+                       (void)printf(" [len %d]", len);
+               break;
+       default:
+               (void)printf("igmp-%d", cp[0] & 0xf);
+               break;
+       }
+       if ((cp[0] >> 4) != 1)
+               (void)printf(" [v%d]", cp[0] >> 4);
+       if (cp[1])
+               (void)printf(" [b1=0x%x]", cp[1]);
+}
+
+/*
+ * print the recorded route in an IP RR, LSRR or SSRR option.
+ */
+static void
+ip_printroute(type, cp, length)
+       char *type;
+       register u_char *cp;
+       int length;
+{
+       int ptr = cp[2] - 1;
+       int len;
+
+       printf(" %s{", type);
+       if ((length + 1) & 3)
+               printf(" [bad length %d]", length);
+       if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
+               printf(" [bad ptr %d]", cp[2]);
+
+       type = "";
+       for (len = 3; len < length; len += 4) {
+               if (ptr == len)
+                       type = "#";
+#ifdef TCPDUMP_ALIGN
+               {
+               struct in_addr addr;
+               bcopy((char *)&cp[len], (char *)&addr, sizeof(addr));
+               printf("%s%s", type, ipaddr_string(&addr));
+               }
+#else
+               printf("%s%s", type, ipaddr_string(&cp[len]));
+#endif
+               type = " ";
+       }
+       printf("%s}", ptr == len? "#" : "");
+}
+
+/*
+ * print IP options.
+ */
+static void
+ip_optprint(cp, length)
+       register u_char *cp;
+       int length;
+{
+       int len;
+
+       for (; length > 0; cp += len, length -= len) {
+               int tt = *cp;
+
+               len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
+               if (&cp[1] >= snapend || cp + len > snapend) {
+                       printf("[|ip]");
+                       return;
+               }
+               switch (tt) {
+
+               case IPOPT_EOL:
+                       printf(" EOL");
+                       if (length > 1)
+                               printf("-%d", length - 1);
+                       return;
+
+               case IPOPT_NOP:
+                       printf(" NOP");
+                       break;
+
+               case IPOPT_TS:
+                       printf(" TS{%d}", len);
+                       break;
+
+               case IPOPT_SECURITY:
+                       printf(" SECURITY{%d}", len);
+                       break;
+
+               case IPOPT_RR:
+                       printf(" RR{%d}=", len);
+                       ip_printroute("RR", cp, len);
+                       break;
+
+               case IPOPT_SSRR:
+                       ip_printroute("SSRR", cp, len);
+                       break;
+
+               case IPOPT_LSRR:
+                       ip_printroute("LSRR", cp, len);
+                       break;
+
+               default:
+                       printf(" IPOPT-%d{%d}", cp[0], len);
+                       break;
+               }
+       }
+}
+
+/*
+ * print an IP datagram.
+ */
+void
+ip_print(ip, length)
+       register struct ip *ip;
+       register int length;
+{
+       register int hlen;
+       register int len;
+       register unsigned char *cp;
+
+#ifdef TCPDUMP_ALIGN
+       static u_char *abuf;
+       /*
+        * The IP header is not word aligned, so copy into abuf.
+        * This will never happen with BPF.  It does happen raw packet
+        * dumps from -r.
+        */
+       if ((int)ip & (sizeof(long)-1)) {
+               if (abuf == 0)
+                       abuf = (u_char *)malloc(snaplen);
+               bcopy((char *)ip, (char *)abuf, min(length, snaplen));
+               snapend += abuf - (u_char *)ip;
+               packetp = abuf;
+               ip = (struct ip *)abuf;
+       }
+#endif
+       if ((u_char *)(ip + 1) > snapend) {
+               printf("[|ip]");
+               return;
+       }
+       if (length < sizeof (struct ip)) {
+               (void)printf("truncated-ip %d", length);
+               return;
+       }
+       hlen = ip->ip_hl * 4;
+
+       NTOHS(ip->ip_len);
+       NTOHS(ip->ip_off);
+       NTOHS(ip->ip_id);
+
+       len = ip->ip_len - hlen;
+       if (length < ip->ip_len)
+               (void)printf("truncated-ip - %d bytes missing!",
+                       ip->ip_len - length);
+
+       /*
+        * If this is fragment zero, hand it to the next higher
+        * level protocol.
+        */
+       if ((ip->ip_off & 0x1fff) == 0) {
+               cp = (unsigned char *)ip + hlen;
+               switch (ip->ip_p) {
+
+               case IPPROTO_TCP:
+                       tcp_print((struct tcphdr *)cp, len, ip);
+                       break;
+               case IPPROTO_UDP:
+                       udp_print((struct udphdr *)cp, len, ip);
+                       break;
+               case IPPROTO_ICMP:
+                       icmp_print((struct icmp *)cp, ip);
+                       break;
+               case IPPROTO_ND:
+                       (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+                               ipaddr_string(&ip->ip_dst));
+                       (void)printf(" nd %d", len);
+                       break;
+               case IPPROTO_EGP:
+                       egp_print((struct egp_packet *)cp, len, ip);
+                       break;
+#ifndef IPPROTO_OSPF
+#define IPPROTO_OSPF 89
+#endif
+               case IPPROTO_OSPF:
+                       ospf_print((struct ospfhdr *)cp, len, ip);
+                       break;
+#ifndef IPPROTO_IGMP
+#define IPPROTO_IGMP 2
+#endif
+               case IPPROTO_IGMP:
+                       igmp_print(cp, len, ip);
+                       break;
+               default:
+                       (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+                               ipaddr_string(&ip->ip_dst));
+                       (void)printf(" ip-proto-%d %d", ip->ip_p, len);
+                       break;
+               }
+       }
+       /*
+        * for fragmented datagrams, print id:size@offset.  On all
+        * but the last stick a "+".  For unfragmented datagrams, note
+        * the don't fragment flag.
+        */
+       if (ip->ip_off & 0x3fff) {
+               /*
+                * if this isn't the first frag, we're missing the
+                * next level protocol header.  print the ip addr.
+                */
+               if (ip->ip_off & 0x1fff)
+                       (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+                                     ipaddr_string(&ip->ip_dst));
+               (void)printf(" (frag %d:%d@%d%s)", ip->ip_id, len,
+                       (ip->ip_off & 0x1fff) * 8,
+                       (ip->ip_off & IP_MF)? "+" : "");
+       } else if (ip->ip_off & IP_DF)
+               (void)printf(" (DF)");
+
+       if (ip->ip_tos)
+               (void)printf(" [tos 0x%x]", (int)ip->ip_tos);
+       if (ip->ip_ttl <= 1)
+               (void)printf(" [ttl %d]", (int)ip->ip_ttl);
+
+       if (vflag) {
+               char *sep = "";
+
+               printf(" (");
+               if (ip->ip_ttl > 1) {
+                       (void)printf("%sttl %d", sep, (int)ip->ip_ttl);
+                       sep = ", ";
+               }
+               if ((ip->ip_off & 0x3fff) == 0) {
+                       (void)printf("%sid %d", sep, (int)ip->ip_id);
+                       sep = ", ";
+               }
+               if ((hlen -= sizeof(struct ip)) > 0) {
+                       (void)printf("%soptlen=%d", sep, hlen);
+                       ip_optprint((u_char *)(ip + 1), hlen);
+               }
+               printf(")");
+       }
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-nfs.c b/usr/src/contrib/tcpdump/tcpdump/print-nfs.c
new file mode 100644 (file)
index 0000000..8b31697
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 1990, 1991, 1992 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-nfs.c,v 1.24 92/01/31 12:27:46 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <sys/time.h>
+#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/svc.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_msg.h>
+
+#include <ctype.h>
+
+#include "interface.h"
+/* These must come after interface.h for BSD. */
+#if BSD >= 199006
+#include <sys/ucred.h>
+#include <nfs/nfsv2.h>
+#endif
+#include <nfs/nfs.h>
+
+#include "addrtoname.h"
+#include "extract.h"
+
+static void nfs_printfh();
+static void nfs_printfn();
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Byte swap an array of n words.
+ * Assume input is word-aligned.
+ * Check that buffer is bounded by "snapend".
+ */
+static void
+bswap(bp, n)
+       register u_long *bp;
+       register u_int n;
+{
+       register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp);
+
+       if (nwords > n)
+               nwords = n;
+       for (; --nwords >= 0; ++bp)
+               *bp = ntohl(*bp);
+}
+#endif
+
+void
+nfsreply_print(rp, length, ip)
+       register struct rpc_msg *rp;
+       int length;
+       register struct ip *ip;
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+       bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+       if (!nflag)
+               (void)printf("%s.nfs > %s.%x: reply %s %d",
+                            ipaddr_string(&ip->ip_src),
+                            ipaddr_string(&ip->ip_dst),
+                            rp->rm_xid,
+                            rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR",
+                            length);
+       else
+               (void)printf("%s.%x > %s.%x: reply %s %d",
+                            ipaddr_string(&ip->ip_src),
+                            NFS_PORT,
+                            ipaddr_string(&ip->ip_dst),
+                            rp->rm_xid,
+                            rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR",
+                            length);
+}
+
+/*
+ * Return a pointer to the first file handle in the packet.
+ * If the packet was truncated, return 0.
+ */
+static u_long *
+parsereq(rp, length)
+       register struct rpc_msg *rp;
+       register int length;
+{
+       register u_long *dp = (u_long *)&rp->rm_call.cb_cred;
+       register u_long *ep = (u_long *)snapend;
+
+       /* 
+        * find the start of the req data (if we captured it) 
+        * note that dp[1] was already byte swapped by bswap()
+        */
+       if (dp < ep && dp[1] < length) {
+               dp += (dp[1] + (2*sizeof(u_long) + 3)) / sizeof(u_long);
+               if ((dp < ep) && (dp[1] < length)) {
+                       dp += (dp[1] + (2*sizeof(u_long) + 3)) /
+                               sizeof(u_long);
+                       if (dp < ep)
+                               return (dp);
+               }
+       }
+       return (0);
+}
+
+/*
+ * Print out an NFS file handle and return a pointer to following word.
+ * If packet was truncated, return 0.
+ */
+static u_long *
+parsefh(dp)
+       register u_long *dp;
+{
+       if (dp + 8 <= (u_long *)snapend) {
+               nfs_printfh(dp);
+               return (dp + 8);
+       }
+       return (0);
+}
+
+/*
+ * Print out a file name and return pointer to longword past it.
+ * If packet was truncated, return 0.
+ */
+static u_long *
+parsefn(dp)
+       register u_long *dp;
+{
+       register int len;
+       register u_char *cp;
+
+       /* Bail if we don't have the string length */
+       if ((u_char *)dp > snapend - sizeof(*dp))
+               return(0);
+
+       /* Fetch string length; convert to host order */
+       len = *dp++;
+       NTOHL(len);
+
+       cp = (u_char *)dp;
+       /* Update long pointer (NFS filenames are padded to long) */
+       dp += ((len + 3) & ~3) / sizeof(*dp);
+       if ((u_char *)dp > snapend)
+               return (0);
+       nfs_printfn(cp, len);
+
+       return (dp);
+}
+
+/*
+ * Print out file handle and file name.
+ * Return pointer to longword past file name.
+ * If packet was truncated (or there was some other error), return 0.
+ */
+static u_long *
+parsefhn(dp)
+       register u_long *dp;
+{
+       dp = parsefh(dp);
+       if (dp == 0)
+               return (0);
+       putchar(' ');
+       return (parsefn(dp));
+}
+
+void
+nfsreq_print(rp, length, ip)
+       register struct rpc_msg *rp;
+       int length;
+       register struct ip *ip;
+{
+       register u_long *dp;
+       register u_char *ep = snapend;
+#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+       bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+
+       if (!nflag)
+               (void)printf("%s.%x > %s.nfs: %d",
+                            ipaddr_string(&ip->ip_src),
+                            rp->rm_xid,
+                            ipaddr_string(&ip->ip_dst),
+                            length);
+       else
+               (void)printf("%s.%x > %s.%x: %d",
+                            ipaddr_string(&ip->ip_src),
+                            rp->rm_xid,
+                            ipaddr_string(&ip->ip_dst),
+                            NFS_PORT,
+                            length);
+
+       switch (rp->rm_call.cb_proc) {
+#ifdef NFSPROC_NOOP
+       case NFSPROC_NOOP:
+               printf(" nop");
+               return;
+#else
+#define NFSPROC_NOOP -1
+#endif
+       case RFS_NULL:
+               printf(" null");
+               return;
+
+       case RFS_GETATTR:
+               printf(" getattr");
+               if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+                       return;
+               break;
+
+       case RFS_SETATTR:
+               printf(" setattr");
+               if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+                       return;
+               break;
+
+#if RFS_ROOT != NFSPROC_NOOP
+       case RFS_ROOT:
+               printf(" root");
+               break;
+#endif
+       case RFS_LOOKUP:
+               printf(" lookup");
+               if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+                       return;
+               break;
+
+       case RFS_READLINK:
+               printf(" readlink");
+               if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+                       return;
+               break;
+
+       case RFS_READ:
+               printf(" read");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefh(dp)) != 0) {
+                       TCHECK(dp, 3 * sizeof(*dp));
+                       printf(" %lu (%lu) bytes @ %lu",
+                              ntohl(dp[1]), ntohl(dp[2]), ntohl(dp[0]));
+                       return;
+               }
+               break;
+
+#if RFS_WRITECACHE != NFSPROC_NOOP
+       case RFS_WRITECACHE:
+               printf(" writecache");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefh(dp)) != 0) {
+                       TCHECK(dp, 4 * sizeof(*dp));
+                       printf(" %lu (%lu) bytes @ %lu (%lu)",
+                              ntohl(dp[3]), ntohl(dp[2]),
+                              ntohl(dp[1]), ntohl(dp[0]));
+                       return;
+               }
+               break;
+#endif
+       case RFS_WRITE:
+               printf(" write");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefh(dp)) != 0) {
+                       TCHECK(dp, 4 * sizeof(*dp));
+                       printf(" %lu (%lu) bytes @ %lu (%lu)",
+                              ntohl(dp[3]), ntohl(dp[2]),
+                              ntohl(dp[1]), ntohl(dp[0]));
+                       return;
+               }
+               break;
+
+       case RFS_CREATE:
+               printf(" create");
+               if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+                       return;
+               break;
+
+       case RFS_REMOVE:
+               printf(" remove");
+               if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+                       return;
+               break;
+
+       case RFS_RENAME:
+               printf(" rename");
+               if ((dp = parsereq(rp, length)) != 0 && 
+                   (dp = parsefhn(dp)) != 0) {
+                       fputs(" ->", stdout);
+                       if (parsefhn(dp) != 0)
+                               return;
+               }
+               break;
+
+       case RFS_LINK:
+               printf(" link");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefh(dp)) != 0) {
+                       fputs(" ->", stdout);
+                       if (parsefhn(dp) != 0)
+                               return;
+               }
+               break;
+
+       case RFS_SYMLINK:
+               printf(" symlink");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefhn(dp)) != 0) {
+                       fputs(" -> ", stdout);
+                       if (parsefn(dp) != 0)
+                               return;
+               }
+               break;
+
+       case RFS_MKDIR:
+               printf(" mkdir");
+               if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+                       return;
+               break;
+
+       case RFS_RMDIR:
+               printf(" rmdir");
+               if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+                       return;
+               break;
+
+       case RFS_READDIR:
+               printf(" readdir");
+               if ((dp = parsereq(rp, length)) != 0 &&
+                   (dp = parsefh(dp)) != 0) {
+                       TCHECK(dp, 2 * sizeof(*dp));
+                       printf(" %lu bytes @ %lu", ntohl(dp[1]), ntohl(dp[0]));
+                       return;
+               }
+               break;
+
+       case RFS_STATFS:
+               printf(" statfs");
+               if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+                       return;
+               break;
+
+       default:
+               printf(" proc-%lu", rp->rm_call.cb_proc);
+               return;
+       }
+       fputs(" [|nfs]", stdout);
+#undef TCHECK
+}
+
+/*
+ * Print out an NFS file handle.
+ * We assume packet was not truncated before the end of the
+ * file handle pointed to by dp.
+ */
+static void
+nfs_printfh(dp)
+       register u_long *dp;
+{
+       /*
+        * take a wild guess at the structure of file handles.
+        * On sun 3s, there are 2 longs of fsid, a short
+        * len == 8, a long of inode & a long of generation number.
+        * On sun 4s, the len == 10 & there are 2 bytes of
+        * padding immediately following it.
+        */
+       if (dp[2] == 0xa0000) {
+               if (dp[1])
+                       (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], dp[3]);
+               else
+                       (void) printf(" fh %ld.%ld", dp[0], dp[3]);
+       } else if ((dp[2] >> 16) == 8)
+               /*
+                * 'dp' is longword aligned, so we must use the extract
+                * macros below for dp+10 which cannot possibly be aligned.
+                */
+               if (dp[1])
+                       (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1],
+                                     EXTRACT_LONG((u_char *)dp + 10));
+               else
+                       (void) printf(" fh %ld.%ld", dp[0],
+                                     EXTRACT_LONG((u_char *)dp + 10));
+       /* On Ultrix pre-4.0, three longs: fsid, fno, fgen and then zeros */
+       else if (dp[3] == 0) {
+               (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
+                            dp[1], dp[2]);
+       }
+       /*
+        * On Ultrix 4.0,
+        * five longs: fsid, fno, fgen, eno, egen and then zeros
+        */
+       else if (dp[5] == 0) {
+               (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
+                            dp[1], dp[2]);
+               if (vflag) {
+                       /* print additional info */
+                       (void)printf("[%ld.%ld]", dp[3], dp[4]);
+               }
+       }
+       else
+               (void) printf(" fh %lu.%lu.%lu.%lu",
+                   dp[0], dp[1], dp[2], dp[3]);
+}
+
+/*
+ * Print out an NFS filename.
+ * Assumes that len bytes from cp are present in packet.
+ */
+static void
+nfs_printfn(cp, len)
+       register u_char *cp;
+       register int len;
+{
+       register char c;
+
+       /* Sanity */
+       if (len >= 64) {
+               fputs("[\">]", stdout);
+               return;
+       }
+       /* Print out the filename */
+       putchar('"');
+       while (--len >= 0) {
+               c = toascii(*cp++);
+               if (!isascii(c)) {
+                       c = toascii(c);
+                       putchar('M');
+                       putchar('-');
+               }
+               if (!isprint(c)) {
+                       c ^= 0x40;      /* DEL to ?, others to alpha */
+                       putchar('^');
+               }
+               putchar(c);
+       }
+       putchar('"');
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-ntp.c b/usr/src/contrib/tcpdump/tcpdump/print-ntp.c
new file mode 100644 (file)
index 0000000..86f6ba7
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print ntp packets.
+ *     By Jeffrey Mogul/DECWRL
+ *     loosely based on print-bootp.c
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-ntp.c,v 1.7 92/01/04 01:45:16 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ntp.h"
+
+/*
+ * Print ntp requests
+ */
+void
+ntp_print(bp, length)
+       register struct ntpdata *bp;
+       int length;
+{
+       u_char *ep;
+       int mode, version, leapind;
+       static char rclock[5];
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+       /* Note funny sized packets */
+       if (length != sizeof(struct ntpdata))
+               (void)printf(" [len=%d]", length);
+
+       /* 'ep' points to the end of avaible data. */
+       ep = (u_char *)snapend;
+
+       TCHECK(bp->status, sizeof(bp->status));
+
+       version = (bp->status & VERSIONMASK) >> 3;
+       printf(" v%d", version);
+
+       leapind = bp->status & LEAPMASK;
+       switch (leapind) {
+
+       case NO_WARNING:
+               break;
+
+       case PLUS_SEC:
+               fputs(" +1s", stdout);
+               break;
+
+       case MINUS_SEC:
+               fputs(" -1s", stdout);
+               break;
+       }
+
+       mode = bp->status & MODEMASK;
+       switch (mode) {
+
+       case MODE_UNSPEC:       /* unspecified */
+               fputs(" unspec", stdout);
+               break;
+
+       case MODE_SYM_ACT:      /* symmetric active */
+               fputs(" sym_act", stdout);
+               break;
+
+       case MODE_SYM_PAS:      /* symmetric passive */
+               fputs(" sym_pas", stdout);
+               break;
+
+       case MODE_CLIENT:       /* client */
+               fputs(" client", stdout);
+               break;
+
+       case MODE_SERVER:       /* server */
+               fputs(" server", stdout);
+               break;
+
+       case MODE_BROADCAST:    /* broadcast */
+               fputs(" bcast", stdout);
+               break;
+
+       case MODE_RES1:         /* reserved */
+               fputs(" res1", stdout);
+               break;
+
+       case MODE_RES2:         /* reserved */
+               fputs(" res2", stdout);
+               break;
+
+       }
+
+       TCHECK(bp->stratum, sizeof(bp->stratum));
+       printf(" strat %d", bp->stratum);
+
+       TCHECK(bp->ppoll, sizeof(bp->ppoll));
+       printf(" poll %d", bp->ppoll);
+
+       /* Can't TCHECK bp->precision bitfield so bp->distance + 0 instead */
+       TCHECK(bp->distance, 0);
+       printf(" prec %d", bp->precision);
+
+       if (!vflag)
+               return;
+
+       TCHECK(bp->distance, sizeof(bp->distance));
+       fputs(" dist ", stdout);
+       p_sfix(&bp->distance);
+
+       TCHECK(bp->dispersion, sizeof(bp->dispersion));
+       fputs(" disp ", stdout);
+       p_sfix(&bp->dispersion);
+
+       TCHECK(bp->refid, sizeof(bp->refid));
+       fputs(" ref ", stdout);
+       /* Interpretation depends on stratum */
+       switch (bp->stratum) {
+
+       case UNSPECIFIED:
+       case PRIM_REF:
+               strncpy(rclock, (char *)&(bp->refid), 4);
+               rclock[4] = '\0';
+               fputs(rclock, stdout);
+               break;
+
+       case INFO_QUERY:
+               printf("%s INFO_QUERY", ipaddr_string(&(bp->refid)));
+               /* this doesn't have more content */
+               return;
+
+       case INFO_REPLY:
+               printf("%s INFO_REPLY", ipaddr_string(&(bp->refid)));
+               /* this is too complex to be worth printing */
+               return;
+
+       default:
+               printf("%s", ipaddr_string(&(bp->refid)));
+               break;
+       }
+
+       TCHECK(bp->reftime, sizeof(bp->reftime));
+       putchar('@');
+       p_ntp_time(&(bp->reftime));
+
+       TCHECK(bp->org, sizeof(bp->org));
+       fputs(" orig ", stdout);
+       p_ntp_time(&(bp->org));
+
+       TCHECK(bp->rec, sizeof(bp->rec));
+       fputs(" rec ", stdout);
+       p_ntp_delta(&(bp->org), &(bp->rec));
+
+       TCHECK(bp->xmt, sizeof(bp->xmt));
+       fputs(" xmt ", stdout);
+       p_ntp_delta(&(bp->org), &(bp->xmt));
+
+       return;
+
+trunc:
+       fputs(" [|ntp]", stdout);
+#undef TCHECK
+}
+
+p_sfix(sfp)
+       register struct s_fixedpt *sfp;
+{
+       register int i;
+       register int f;
+       register float ff;
+
+       i = ntohs(sfp->int_part);
+       f = ntohs(sfp->fraction);
+       ff = f / 65536.0;       /* shift radix point by 16 bits */
+       f = ff * 1000000.0;     /* Treat fraction as parts per million */
+       printf("%d.%06d", i, f);
+}
+
+#define        FMAXINT (4294967296.0)  /* floating point rep. of MAXINT */
+
+p_ntp_time(lfp)
+       register struct l_fixedpt *lfp;
+{
+       register long i;
+       register unsigned long uf;
+       register unsigned long f;
+       register float ff;
+
+       i = ntohl(lfp->int_part);
+       uf = ntohl(lfp->fraction);
+       ff = uf;
+       if (ff < 0.0)           /* some compilers are buggy */
+               ff += FMAXINT;
+       ff = ff / FMAXINT;      /* shift radix point by 32 bits */
+       f = ff * 1000000000.0;  /* treat fraction as parts per billion */
+       printf("%lu.%09d", i, f);
+}
+
+/* Prints time difference between *lfp and *olfp */
+p_ntp_delta(olfp, lfp)
+       register struct l_fixedpt *olfp;
+       register struct l_fixedpt *lfp;
+{
+       register long i;
+       register unsigned long uf;
+       register unsigned long ouf;
+       register unsigned long f;
+       register float ff;
+       int signbit;
+
+       i = ntohl(lfp->int_part) - ntohl(olfp->int_part);
+
+       uf = ntohl(lfp->fraction);
+       ouf = ntohl(olfp->fraction);
+
+       if (i > 0) {            /* new is definitely greater than old */
+               signbit = 0;
+               f = uf - ouf;
+               if (ouf > uf)   /* must borrow from high-order bits */
+                       i -= 1;
+       } else if (i < 0) {     /* new is definitely less than old */
+               signbit = 1;
+               f = ouf - uf;
+               if (uf > ouf)   /* must carry into the high-order bits */
+                       i += 1;
+               i = -i;
+       } else {                /* int_part is zero */
+               if (uf > ouf) {
+                       signbit = 0;
+                       f = uf - ouf;
+               } else {
+                       signbit = 1;
+                       f = ouf - uf;
+               }
+       }
+
+       ff = f;
+       if (ff < 0.0)           /* some compilers are buggy */
+               ff += FMAXINT;
+       ff = ff / FMAXINT;      /* shift radix point by 32 bits */
+       f = ff * 1000000000.0;  /* treat fraction as parts per billion */
+       if (signbit)
+               putchar('-');
+       else
+               putchar('+');
+       printf("%d.%09d", i, f);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-null.c b/usr/src/contrib/tcpdump/tcpdump/print-null.c
new file mode 100644 (file)
index 0000000..b186068
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#)$Header: print-null.c,v 1.3 91/10/07 20:19:11 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#define        NULL_HDRLEN 4
+
+static void
+null_print(p, ip, length)
+       u_char *p;
+       struct ip *ip;
+       int length;
+{
+       u_int family;
+
+       bcopy(p, &family, sizeof(family));
+
+       if (nflag) {
+               /* XXX just dump the header */
+               return;
+       }
+       switch (family) {
+
+       case AF_INET:
+               printf("ip: ");
+               break;
+
+       case AF_NS:
+               printf("ns: ");
+               break;
+
+       default:
+               printf("AF %d: ", family);
+               break;
+       }
+}
+
+void
+null_if_print(p, tvp, length, caplen)
+       u_char *p;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct ip *ip;
+
+       ts_print(tvp);
+
+       /*
+        * Some printers want to get back at the link level addresses,
+        * and/or check that they're not walking off the end of the packet.
+        * Rather than pass them all the way down, we set these globals.
+        */
+       packetp = (u_char *)p;
+       snapend = (u_char *)p + caplen;
+
+       length -= NULL_HDRLEN;
+
+       ip = (struct ip *)(p + NULL_HDRLEN);
+
+       if (eflag)
+               null_print(p, ip, length);
+
+       ip_print(ip, length);
+
+       if (xflag)
+               default_print((u_short *)ip, caplen - NULL_HDRLEN);
+       putchar('\n');
+}
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-ospf.c b/usr/src/contrib/tcpdump/tcpdump/print-ospf.c
new file mode 100644 (file)
index 0000000..90daf94
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 1991 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-ospf.c,v 1.1 92/01/29 12:44:17 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <errno.h>
+#include <ctype.h>
+
+#include "ospf.h"
+#include "interface.h"
+#include "addrtoname.h"
+
+#ifndef        __GNUC__
+#define        inline
+#endif
+
+#if    !defined(__STDC__) && !defined(const)
+#define        const
+#endif /* !defined(__STDC__) && !defined(const) */
+
+struct bits {
+    u_long bit;
+    const char *str;
+};
+
+static const struct bits ospf_option_bits[] = {
+    OSPF_OPTION_T,     "T",
+    OSPF_OPTION_E,     "E",
+    OSPF_OPTION_MC,    "MC",
+    0,                 (char *) 0
+};
+
+static const struct bits ospf_rla_flag_bits[] = {
+    RLA_FLAG_B,                "B",
+    RLA_FLAG_E,                "E",
+    RLA_FLAG_W1,       "W1",
+    RLA_FLAG_W2,       "W2",
+    0,                 (char *) 0
+};
+
+static const char *ospf_types[OSPF_TYPE_MAX] = {
+  (char *) 0,
+  "hello",
+  "dd",
+  "ls_req",
+  "ls_upd",
+  "ls_ack"
+};
+
+static inline void
+ospf_print_seqage(seq, us)
+register u_long seq;
+register time_t us;
+{
+    register time_t sec = us % 60;
+    register time_t mins = (us / 60) % 60;
+    register time_t hour = us/3600;
+
+    printf(" S %X age ",
+          seq);
+    if (hour) {
+       printf("%d:%02d:%02d",
+              hour,
+              mins,
+              sec);
+    } else if (mins) {
+       printf("%d:%02d",
+              mins,
+              sec);
+    } else {
+       printf("%d",
+              sec);
+    }
+}
+
+
+static inline void
+ospf_print_bits(bp, options)
+register struct bits *bp;
+register u_char options;
+{
+    char sep = ' ';
+
+    do {
+       if (options & bp->bit) {
+           printf("%c%s",
+                  sep,
+                  bp->str);
+           sep = '/';
+       }
+    } while ((++bp)->bit) ;
+}
+
+
+#define        LS_PRINT(lsp, type) switch (type) { \
+    case LS_TYPE_ROUTER: \
+       printf(" rtr %s ", ipaddr_string(&lsp->ls_router)); break; \
+    case LS_TYPE_NETWORK: \
+       printf(" net dr %s if %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \
+    case LS_TYPE_SUM_IP: \
+       printf(" sum %s abr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+    case LS_TYPE_SUM_ABR: \
+       printf(" abr %s rtr %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \
+    case LS_TYPE_ASE: \
+       printf(" ase %s asbr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+    case LS_TYPE_GROUP: \
+       printf(" group %s rtr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \
+    }
+
+static int
+ospf_print_lshdr(lshp, end)
+register struct lsa_hdr *lshp;
+caddr_t end;
+{
+    if ((caddr_t) (lshp + 1) > end) {
+       return 1;
+    }
+    
+    printf(" {");
+
+    if (!lshp->ls_type || lshp->ls_type >= LS_TYPE_MAX) {
+       printf(" ??LS type %d?? }",
+              lshp->ls_type);
+       return 1;
+    }
+
+    ospf_print_bits(ospf_option_bits, lshp->ls_options);
+    ospf_print_seqage(ntohl(lshp->ls_seq),
+                         ntohs(lshp->ls_age));
+
+    LS_PRINT(lshp, lshp->ls_type);
+
+    return 0;
+}
+
+
+/*
+ * Print a single link state advertisement.  If truncated return 1, else 0.
+ */
+
+static int
+ospf_print_lsa(lsap, end)
+register struct lsa *lsap;
+caddr_t        end;
+{
+    register caddr_t ls_end;
+    struct rlalink *rlp;
+    struct tos_metric *tosp;
+    struct in_addr *ap;
+    struct aslametric *almp;
+    struct mcla *mcp;
+    u_long *lp;
+    int j, k;
+
+    if (ospf_print_lshdr(&lsap->ls_hdr, end)) {
+       return 1;
+    }
+
+    ls_end = (caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length);
+    
+    if (ls_end > end) {
+       printf(" }");
+       return 1;
+    }
+
+    switch (lsap->ls_hdr.ls_type) {
+    case LS_TYPE_ROUTER:
+       ospf_print_bits(ospf_rla_flag_bits, lsap->lsa_un.un_rla.rla_flags);
+
+       j = ntohs(lsap->lsa_un.un_rla.rla_count);
+       rlp = lsap->lsa_un.un_rla.rla_link;
+       while (j--) {
+           struct rlalink *rln = (struct rlalink *) ((caddr_t) (rlp + 1) + ((rlp->link_toscount) * sizeof (struct tos_metric)));
+
+           if ((caddr_t) rln > ls_end) {
+               break;
+           }
+           printf(" {");
+
+           switch (rlp->link_type) {
+           case RLA_TYPE_VIRTUAL:
+               printf(" virt");
+               /* Fall through */
+               
+           case RLA_TYPE_ROUTER:
+               printf(" nbrid %s if %s",
+                      ipaddr_string(&rlp->link_id),
+                      ipaddr_string(&rlp->link_data));
+               break;
+
+           case RLA_TYPE_TRANSIT:
+               printf(" dr %s if %s",
+                      ipaddr_string(&rlp->link_id),
+                      ipaddr_string(&rlp->link_data));
+               break;
+
+           case RLA_TYPE_STUB:
+               printf(" net %s mask %s",
+                      ipaddr_string(&rlp->link_id),
+                      ipaddr_string(&rlp->link_data));
+               break;
+
+           default:
+               printf(" ??RouterLinksType %d?? }",
+                      rlp->link_type);
+               return 0;
+           }
+           printf(" tos 0 metric %d",
+                  ntohs(rlp->link_tos0metric));
+           tosp = (struct tos_metric *) ((sizeof rlp->link_tos0metric) + (caddr_t) rlp);
+           for (k = 0; k < rlp->link_toscount; k++, tosp++) {
+               printf(" tos %d metric %d",
+                      ntohs(tosp->tos_type),
+                      ntohs(tosp->tos_metric));
+           }
+           printf(" }");
+           rlp = rln;
+       }
+       break; 
+
+    case LS_TYPE_NETWORK: 
+       printf(" mask %s rtrs",
+              ipaddr_string(&lsap->lsa_un.un_nla.nla_mask));
+       for (ap = lsap->lsa_un.un_nla.nla_router;
+            (caddr_t) (ap + 1) <= ls_end;
+            ap++) {
+           printf(" %s",
+                  ipaddr_string(ap));
+       }
+       break; 
+
+    case LS_TYPE_SUM_IP: 
+       printf(" mask %s",
+              ipaddr_string(&lsap->lsa_un.un_sla.sla_mask));
+       /* Fall through */
+
+    case LS_TYPE_SUM_ABR:
+
+       for (lp = lsap->lsa_un.un_sla.sla_tosmetric;
+            (caddr_t) (lp + 1) <= ls_end;
+            lp++) {
+           u_long ul = ntohl(*lp);
+
+           printf(" tos %d metric %d",
+                  (ul & SLA_MASK_TOS) >> SLA_SHIFT_TOS,
+                  ul & SLA_MASK_METRIC);
+       }
+       break;
+
+    case LS_TYPE_ASE:
+       printf(" mask %s",
+              ipaddr_string(&lsap->lsa_un.un_asla.asla_mask));
+
+       for (almp = lsap->lsa_un.un_asla.asla_metric;
+            (caddr_t) (almp + 1) <= ls_end;
+            almp++) {
+           u_long ul = ntohl(almp->asla_tosmetric);
+
+           printf(" type %d tos %d metric %d",
+                  (ul & ASLA_FLAG_EXTERNAL) ? 2 : 1,
+                  (ul & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS,
+                  (ul & ASLA_MASK_METRIC));
+           if (almp->asla_forward.s_addr) {
+               printf(" forward %s",
+                      ipaddr_string(&almp->asla_forward));
+           }
+           if (almp->asla_tag.s_addr) {
+               printf(" tag %s",
+                      ipaddr_string(&almp->asla_tag));
+           }
+       }
+       break;
+
+    case LS_TYPE_GROUP:
+       /* Multicast extensions as of 23 July 1991 */
+       for (mcp = lsap->lsa_un.un_mcla;
+            (caddr_t) (mcp + 1) <= ls_end;
+            mcp++) {
+           switch (ntohl(mcp->mcla_vtype)) {
+           case MCLA_VERTEX_ROUTER:
+               printf(" rtr rtrid %s",
+                      ipaddr_string(&mcp->mcla_vid));
+               break;
+
+           case MCLA_VERTEX_NETWORK:
+               printf(" net dr %s",
+                      ipaddr_string(&mcp->mcla_vid));
+               break;
+
+           default:
+               printf(" ??VertexType %d??",
+                      ntohl(mcp->mcla_vtype));
+               break;
+           }
+       }
+    }
+
+    printf(" }");
+    return 0;
+}
+
+
+void
+ospf_print(dat, length, ip)
+u_char *dat;
+int length;
+struct ip *ip;
+{
+    register struct ospfhdr *op = (struct ospfhdr *) dat;
+    register caddr_t end = (caddr_t)snapend;
+    register struct lsa *lsap;
+    register struct lsa_hdr *lshp;
+    char sep;
+    int i, j;
+    struct in_addr *ap;
+    struct lsr *lsrp;
+
+    /* Print the source and destination address        */
+    (void) printf(" %s > %s:",
+                 ipaddr_string(&ip->ip_src),
+                 ipaddr_string(&ip->ip_dst));
+
+    if ((caddr_t) (&op->ospf_len + 1) > end) {
+       goto trunc_test;
+    }
+
+    /* If the type is valid translate it, or just print the type */
+    /* value.  If it's not valid, say so and return */
+    if (op->ospf_type || op->ospf_type < OSPF_TYPE_MAX) {
+       printf(" OSPFv%d-%s %d:",
+              op->ospf_version,
+              ospf_types[op->ospf_type],
+              length);
+    } else {
+       printf(" ospf-v%d-??type %d?? %d:",
+              op->ospf_version,
+              op->ospf_type,
+              length);
+       return;
+    }
+
+    if (length != ntohs(op->ospf_len)) {
+       printf(" ??len %d??",
+              ntohs(op->ospf_len));
+       goto trunc_test;
+    }
+       
+    if ((caddr_t) (&op->ospf_routerid + 1) > end) {
+       goto trunc_test;
+    }
+    
+    /* Print the routerid if it is not the same as the source */
+    if (ip->ip_src.s_addr != op->ospf_routerid.s_addr) {
+       printf(" rtrid %s",
+              ipaddr_string(&op->ospf_routerid));
+    }
+
+    if ((caddr_t) (&op->ospf_areaid + 1) > end) {
+       goto trunc_test;
+    }
+
+    if (op->ospf_areaid.s_addr) {
+       printf(" area %s",
+              ipaddr_string(&op->ospf_areaid));
+    } else {
+       printf(" backbone");
+    }
+
+    if ((caddr_t) (op->ospf_authdata + OSPF_AUTH_SIZE) > end) {
+       goto trunc_test;
+    }
+
+    if (vflag) {
+       /* Print authentication data (should we really do this?) */
+       switch (ntohs(op->ospf_authtype)) {
+       case OSPF_AUTH_NONE:
+           break;
+
+       case OSPF_AUTH_SIMPLE:
+           printf(" auth ");
+           j = 0;
+           for (i = 0; i < sizeof (op->ospf_authdata); i++) {
+               if (!isprint(op->ospf_authdata[i])) {
+                   j = 1;
+                   break;
+               }
+           }
+           if (j) {
+               /* Print the auth-data as a string of octets */
+               printf("%s.%s",
+                      ipaddr_string((struct in_addr *) op->ospf_authdata),
+                      ipaddr_string((struct in_addr *) &op->ospf_authdata[sizeof (struct in_addr)]));
+           } else {
+               /* Print the auth-data as a text string */
+               printf("'%.8s'",
+                      op->ospf_authdata);
+           }
+           break;
+
+       default:
+           printf(" ??authtype-%d??",
+                  ntohs(op->ospf_authtype));
+           return;
+       }
+    }
+
+
+    /* Do rest according to version.   */
+    switch (op->ospf_version) {
+    case 2:
+        /* ospf version 2      */
+       switch (op->ospf_type) {
+       case OSPF_TYPE_UMD:             /* Rob Coltun's special monitoring packets; do nothing  */
+           break;
+
+       case OSPF_TYPE_HELLO:
+           if ((caddr_t) (&op->ospf_hello.hello_deadint + 1) > end) {
+               break;
+           }
+           if (vflag) {
+               ospf_print_bits(ospf_option_bits, op->ospf_hello.hello_options);
+               printf(" mask %s int %d pri %d dead %d",
+                      ipaddr_string(&op->ospf_hello.hello_mask),
+                      ntohs(op->ospf_hello.hello_helloint),
+                      op->ospf_hello.hello_priority,
+                      ntohl(op->ospf_hello.hello_deadint));
+           }
+
+           if ((caddr_t) (&op->ospf_hello.hello_dr + 1) > end) {
+               break;
+           }
+           if (op->ospf_hello.hello_dr.s_addr) {
+               printf(" dr %s",
+                      ipaddr_string(&op->ospf_hello.hello_dr));
+           }
+
+           if ((caddr_t) (&op->ospf_hello.hello_bdr + 1) > end) {
+               break;
+           }
+           if (op->ospf_hello.hello_bdr.s_addr) {
+               printf(" bdr %s",
+                      ipaddr_string(&op->ospf_hello.hello_bdr));
+           }
+
+           if (vflag) {
+               if ((caddr_t) (op->ospf_hello.hello_neighbor + 1) > end) {
+                   break;
+               }
+               printf(" nbrs");
+               for (ap = op->ospf_hello.hello_neighbor;
+                    (caddr_t) (ap + 1) <= end;
+                    ap++) {
+                   printf(" %s",
+                          ipaddr_string(ap));
+               }
+           }
+           break;                      /*  HELLO       */
+
+       case OSPF_TYPE_DB:
+           if ((caddr_t) (&op->ospf_db.db_seq + 1) > end) {
+               break;
+           }
+           ospf_print_bits(ospf_option_bits, op->ospf_db.db_options);
+           sep = ' ';
+           if (op->ospf_db.db_flags & OSPF_DB_INIT) {
+               printf("%cI",
+                      sep);
+               sep = '/';
+           }
+           if (op->ospf_db.db_flags & OSPF_DB_MORE) {
+               printf("%cM",
+                      sep);
+               sep = '/';
+           }
+           if (op->ospf_db.db_flags & OSPF_DB_MASTER) {
+               printf("%cMS",
+                      sep);
+               sep = '/';
+           }
+           printf(" S %X",
+                  ntohl(op->ospf_db.db_seq));
+
+           if (vflag) {
+               /* Print all the LS adv's */
+               lshp = op->ospf_db.db_lshdr;
+
+               while (!ospf_print_lshdr(lshp, end)) {
+                   printf(" }");
+                   lshp++;
+               }
+           }
+           break;
+
+       case OSPF_TYPE_LSR:
+           if (vflag) {
+               for (lsrp = op->ospf_lsr; (caddr_t) (lsrp+1) <= end; lsrp++) {
+                   long type;
+
+                   if ((caddr_t) (lsrp + 1) > end) {
+                       break;
+                   }
+
+                   printf(" {");
+                   if (!(type = lsrp->ls_type) || type >= LS_TYPE_MAX) {
+                       printf(" ??LinkStateType %d }",
+                              type);
+                       printf(" }");
+                       break;
+                   }
+
+                   LS_PRINT(lsrp, type);
+                   printf(" }");
+               }
+           }
+           break;
+
+       case OSPF_TYPE_LSU:
+           if (vflag) {
+               lsap = op->ospf_lsu.lsu_lsa;
+               i = ntohl(op->ospf_lsu.lsu_count);
+
+               while (i-- &&
+                      !ospf_print_lsa(lsap, end)) {
+                   lsap = (struct lsa *) ((caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length));
+               }
+           }
+           break;
+
+
+       case OSPF_TYPE_LSA:
+           if (vflag) {
+               lshp = op->ospf_lsa.lsa_lshdr;
+
+               while (!ospf_print_lshdr(lshp, end)) {
+                   printf(" }");
+                   lshp++;
+               }
+               break;
+           }
+       }                       /* end switch on v2 packet type */
+       break;
+
+    default:
+       printf(" ospf [version %d]",
+              op->ospf_version);
+       break;
+    }                                  /* end switch on version        */
+
+  trunc_test:
+    if ((snapend - dat) < length) {
+       printf(" [|]");
+    }
+
+    return;                            /* from ospf_print      */
+}
+
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-ppp.c b/usr/src/contrib/tcpdump/tcpdump/print-ppp.c
new file mode 100644 (file)
index 0000000..c83cc7d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static  char rcsid[] =
+       "@(#)$Header: print-ppp.c,v 1.7 91/10/07 20:18:33 leres Exp $ (LBL)";
+#endif
+
+#ifdef PPP
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/* XXX This goes somewhere else. */
+#define PPP_HDRLEN 4
+
+void
+ppp_if_print(p, tvp, length, caplen)
+       u_char *p;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct ip *ip;
+
+       ts_print(tvp);
+
+       if (caplen < PPP_HDRLEN) {
+               printf("[|ppp]");
+               goto out;
+       }
+
+       /*
+        * Some printers want to get back at the link level addresses,
+        * and/or check that they're not walking off the end of the packet.
+        * Rather than pass them all the way down, we set these globals.
+        */
+       packetp = (u_char *)p;
+       snapend = (u_char *)p + caplen;
+
+       if (eflag)
+               printf("%c %4d %02x %04x: ", p[0] ? 'O' : 'I', length,
+                      p[1], ntohs(*(u_short *)&p[2]));
+
+       length -= PPP_HDRLEN;
+       ip = (struct ip *)(p + PPP_HDRLEN);
+       ip_print(ip, length);
+
+       if (xflag)
+               default_print((u_short *)ip, caplen - PPP_HDRLEN);
+out:
+       putchar('\n');
+}
+#else
+#include <stdio.h>
+void
+ppp_if_print()
+{
+       void error();
+
+       error("not configured for ppp");
+       /* NOTREACHED */
+}
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-rip.c b/usr/src/contrib/tcpdump/tcpdump/print-rip.c
new file mode 100644 (file)
index 0000000..d123fe9
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-rip.c,v 1.12 91/04/19 10:46:46 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <protocols/routed.h>
+
+#include <errno.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static void
+rip_entry_print(ni)
+       register struct netinfo *ni;
+{
+       if (ntohs(ni->rip_dst.sa_family) != AF_INET) {
+               register int i;
+
+               printf(" [family %d:", ntohs(ni->rip_dst.sa_family));
+               for (i = 0; i < 14; i += 2)
+                       printf(" %02x%02x", ni->rip_dst.sa_data[i],
+                               ni->rip_dst.sa_data[i+1]);
+               printf("]");
+       } else {
+               register struct sockaddr_in *sin = 
+                               (struct sockaddr_in *)&ni->rip_dst;
+               printf(" %s", ipaddr_string(&sin->sin_addr));
+               if (sin->sin_port)
+                       printf(" [port %d]", sin->sin_port);
+       }
+       printf("(%d)", ntohl(ni->rip_metric));
+}
+
+void
+rip_print(dat, length)
+       u_char *dat;
+       int length;
+{
+       register struct rip *rp = (struct rip *)dat;
+       register struct netinfo *ni;
+       register int amt = (u_char *)snapend - dat;
+       register int i = min(length, amt) -
+                        (sizeof(struct rip) - sizeof(struct netinfo));
+       int j;
+       int trunc;
+       
+       if (i < 0)
+               return;
+
+       switch (rp->rip_cmd) {
+
+       case RIPCMD_REQUEST:
+               printf(" rip-req %d", length);
+               break;
+       case RIPCMD_RESPONSE:
+               j = length / sizeof(*ni);
+               if (j * sizeof(*ni) != length - 4)
+                       printf(" rip-resp %d[%d]:", j, length);
+               else
+                       printf(" rip-resp %d:", j);
+               trunc = ((i / sizeof(*ni)) * sizeof(*ni) != i);
+               for (ni = rp->rip_nets; (i -= sizeof(*ni)) >= 0; ++ni)
+                       rip_entry_print(ni);
+               if (trunc)
+                       printf("[|rip]");
+               break;
+       case RIPCMD_TRACEON:
+               printf(" rip-traceon %d: \"%s\"", length, rp->rip_tracefile);
+               break;
+       case RIPCMD_TRACEOFF:
+               printf(" rip-traceoff %d", length);
+               break;
+       case RIPCMD_POLL:
+               printf(" rip-poll %d", length);
+               break;
+       case RIPCMD_POLLENTRY:
+               printf(" rip-pollentry %d", length);
+               break;
+       default:
+               printf(" rip-%d ?? %d", rp->rip_cmd, length);
+               break;
+       }
+       if (rp->rip_vers != RIPVERSION)
+               printf(" [vers %d]", rp->rip_vers);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-sl.c b/usr/src/contrib/tcpdump/tcpdump/print-sl.c
new file mode 100644 (file)
index 0000000..2c89b42
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static  char rcsid[] =
+       "@(#)$Header: print-sl.c,v 1.17 91/10/07 20:18:35 leres Exp $ (LBL)";
+#endif
+
+#ifdef CSLIP
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <net/slcompress.h>
+#include <net/slip.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static int lastlen[2][256];
+static int lastconn = 255;
+
+static void compressed_sl_print();
+
+void
+sl_if_print(p, tvp, length, caplen)
+       u_char *p;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct ip *ip;
+
+       ts_print(tvp);
+
+       if (caplen < SLIP_HDRLEN) {
+               printf("[|slip]");
+               goto out;
+       }
+       /*
+        * Some printers want to get back at the link level addresses,
+        * and/or check that they're not walking off the end of the packet.
+        * Rather than pass them all the way down, we set these globals.
+        */
+       packetp = (u_char *)p;
+       snapend = (u_char *)p + caplen;
+
+       length -= SLIP_HDRLEN;
+
+       ip = (struct ip *)(p + SLIP_HDRLEN);
+
+       if (eflag)
+               sliplink_print(p, ip, length);
+
+       ip_print(ip, length);
+
+       if (xflag)
+               default_print((u_short *)ip, caplen - SLIP_HDRLEN);
+ out:
+       putchar('\n');
+}
+
+sliplink_print(p, ip, length)
+       u_char *p;
+       struct ip *ip;
+       int length;
+{
+       int dir;
+       int hlen;
+
+       dir = p[SLX_DIR];
+       putchar(dir == SLIPDIR_IN ? 'I' : 'O');
+       putchar(' ');
+
+       if (nflag) {
+               /* XXX just dump the header */
+               int i;
+
+               for (i = 0; i < 15; ++i)
+                       printf("%02x.", p[SLX_CHDR + i]);
+               printf("%02x: ", p[SLX_CHDR + 15]);
+               return;
+       }
+       switch (p[SLX_CHDR] & 0xf0) {
+
+       case TYPE_IP:
+               printf("ip %d: ", length + SLIP_HDRLEN);
+               break;
+
+       case TYPE_UNCOMPRESSED_TCP:
+               /*
+                * The connection id is stode in the IP protcol field.
+                */
+               lastconn = ip->ip_p;
+               hlen = ip->ip_hl;
+               hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
+               lastlen[dir][lastconn] = length - (hlen << 2);
+               printf("utcp %d: ", lastconn);
+               break;
+
+       default:
+               if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
+                       compressed_sl_print(&p[SLX_CHDR], ip, length, dir);
+                       printf(": ");
+               } else
+                       printf("slip-%d!: ", p[SLX_CHDR]);
+       }
+}
+
+static u_char *
+print_sl_change(str, cp)
+       char *str;
+       register u_char *cp;
+{
+       register u_int i;
+
+       if ((i = *cp++) == 0) {
+               i = (cp[0] << 8) | cp[1];
+               cp += 2;
+       }
+       printf(" %s%d", str, i);
+       return (cp);
+}
+
+static u_char *
+print_sl_winchange(cp)
+       register u_char *cp;
+{
+       register short i;
+
+       if ((i = *cp++) == 0) {
+               i = (cp[0] << 8) | cp[1];
+               cp += 2;
+       }
+       if (i >= 0)
+               printf(" W+%d", i);
+       else
+               printf(" W%d", i);
+       return (cp);
+}
+
+static void
+compressed_sl_print(chdr, ip, length, dir)
+       u_char *chdr;
+       int length;
+       struct ip *ip;
+       int dir;
+{
+       register u_char *cp = chdr;
+       register u_int flags;
+       int hlen;
+       
+       flags = *cp++;
+       if (flags & NEW_C) {
+               lastconn = *cp++;
+               printf("ctcp %d", lastconn);
+       } else
+               printf("ctcp *");
+
+       /* skip tcp checksum */
+       cp += 2;
+
+       switch (flags & SPECIALS_MASK) {
+       case SPECIAL_I:
+               printf(" *SA+%d", lastlen[dir][lastconn]);
+               break;
+
+       case SPECIAL_D:
+               printf(" *S+%d", lastlen[dir][lastconn]);
+               break;
+
+       default:
+               if (flags & NEW_U)
+                       cp = print_sl_change("U=", cp);
+               if (flags & NEW_W)
+                       cp = print_sl_winchange(cp);
+               if (flags & NEW_A)
+                       cp = print_sl_change("A+", cp);
+               if (flags & NEW_S)
+                       cp = print_sl_change("S+", cp);
+               break;
+       }
+       if (flags & NEW_I)
+               cp = print_sl_change("I+", cp);
+
+       /*
+        * 'hlen' is the length of the uncompressed TCP/IP header (in longs).
+        * 'cp - chdr' is the length of the compressed header.
+        * 'length - hlen' is the amount of data in the packet.
+        */
+       hlen = ip->ip_hl;
+       hlen += ((struct tcphdr *)&((long *)ip)[hlen])->th_off;
+       lastlen[dir][lastconn] = length - (hlen << 2);
+       printf(" %d (%d)", lastlen[dir][lastconn], cp - chdr);
+}
+#else
+#include <stdio.h>
+void
+sl_if_print()
+{
+       void error();
+
+       error("not configured for slip");
+       /* NOTREACHED */
+}
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-snmp.c b/usr/src/contrib/tcpdump/tcpdump/print-snmp.c
new file mode 100644 (file)
index 0000000..d1996c0
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+ * Copyright (c) 1990, by John Robert LoVerso.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by John Robert LoVerso.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This implementaion has been influenced by the CMU SNMP release,
+ * by Steve Waldbusser.  However, this shares no code with that system.
+ * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
+ * Earlier forms of this implemention were derived and/or inspired by an
+ * awk script originally written by C. Philip Wood of LANL (but later
+ * heavily modified by John Robert LoVerso).  The copyright notice for
+ * that work is preserved below, even though it may not rightly apply
+ * to this file.
+ *
+ * This started out as a very simple program, but the incremental decoding
+ * (into the BE structure) complicated things.
+ *
+ #                     Los Alamos National Laboratory
+ #
+ #     Copyright, 1990.  The Regents of the University of California.
+ #     This software was produced under a U.S. Government contract
+ #     (W-7405-ENG-36) by Los Alamos National Laboratory, which is
+ #     operated by the University of California for the U.S. Department
+ #     of Energy.  The U.S. Government is licensed to use, reproduce,
+ #     and distribute this software.  Permission is granted to the
+ #     public to copy and use this software without charge, provided
+ #     that this Notice and any statement of authorship are reproduced
+ #     on all copies.  Neither the Government nor the University makes
+ #     any warranty, express or implied, or assumes any liability or
+ #     responsibility for the use of this software.
+ #     @(#)snmp.awk.x  1.1 (LANL) 1/15/90
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/*
+ * Universal ASN.1 types
+ * (we only care about the tag values for those allowed in the Internet SMI)
+ */
+char *Universal[] = {
+       "U-0",
+       "Boolean",
+       "Integer",
+#define INTEGER 2
+       "Bitstring",
+       "String",
+#define STRING 4
+       "Null",
+#define ASN_NULL 5
+       "ObjID",
+#define OBJECTID 6
+       "ObjectDes",
+       "U-8","U-9","U-10","U-11",      /* 8-11 */
+       "U-12","U-13","U-14","U-15",    /* 12-15 */
+       "Sequence",
+#define SEQUENCE 16
+       "Set"
+};
+
+/*
+ * Application-wide ASN.1 types from the Internet SMI and their tags
+ */
+char *Application[] = {
+       "IpAddress",
+#define IPADDR 0
+       "Counter",
+#define COUNTER 1
+       "Gauge",
+#define GAUGE 2
+       "TimeTicks",
+#define TIMETICKS 3
+       "Opaque"
+};
+
+/*
+ * Context-specific ASN.1 types for the SNMP PDUs and their tags
+ */
+char *Context[] = {
+       "GetRequest",
+#define GETREQ 0
+       "GetNextRequest",
+#define GETNEXTREQ 1
+       "GetResponse",
+#define GETRESP 2
+       "SetRequest",
+#define SETREQ 3
+       "Trap"
+#define TRAP 4
+};
+
+/*
+ * Private ASN.1 types
+ * The Internet SMI does not specify any
+ */
+char *Private[] = {
+       "P-0"
+};
+
+/*
+ * error-status values for any SNMP PDU
+ */
+char *ErrorStatus[] = {
+       "noError",
+       "tooBig",
+       "noSuchName",
+       "badValue",
+       "readOnly",
+       "genErr"
+};
+#define DECODE_ErrorStatus(e) \
+       ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
+       ? ErrorStatus[e] : (sprintf(errbuf, "err=%d", e), errbuf))
+
+/*
+ * generic-trap values in the SNMP Trap-PDU
+ */
+char *GenericTrap[] = {
+       "coldStart",
+       "warmStart",
+       "linkDown",
+       "linkUp",
+       "authenticationFailure",
+       "egpNeighborLoss",
+       "enterpriseSpecific"
+#define GT_ENTERPRISE 7
+};
+#define DECODE_GenericTrap(t) \
+       ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
+       ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
+
+/*
+ * ASN.1 type class table
+ * Ties together the preceding Universal, Application, Context, and Private
+ * type definitions.
+ */
+#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
+struct {
+       char    *name;
+       char    **Id;
+       int     numIDs;
+} Class[] = {
+       defineCLASS(Universal),
+#define        UNIVERSAL       0
+       defineCLASS(Application),
+#define        APPLICATION     1
+       defineCLASS(Context),
+#define        CONTEXT         2
+       defineCLASS(Private),
+#define        PRIVATE         3
+};
+
+/*
+ * defined forms for ASN.1 types
+ */
+char *Form[] = {
+       "Primitive",
+#define PRIMITIVE      0
+       "Constructed",
+#define CONSTRUCTED    1
+};
+
+/*
+ * A structure for the OID tree for the compiled-in MIB.
+ * This is stored as a general-order tree.
+ */
+struct obj {
+       char    *desc;                  /* name of object */
+       u_char  oid;                    /* sub-id following parent */
+       u_char  type;                   /* object type (unused) */
+       struct obj *child, *next;       /* child and next sibling pointers */
+} *objp = NULL;
+
+/*
+ * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
+ * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
+ * a value for `mibroot'.
+ *
+ * In particluar, this is gross, as this is including initialized structures,
+ * and by right shouldn't be an "include" file.
+ */
+#include "mib.h"
+
+/*
+ * This defines a list of OIDs which will be abreviated on output.
+ * Currently, this includes the prefixes for the Internet MIB, the
+ * private enterprises tree, and the experimental tree.
+ */
+struct obj_abrev {
+       char *prefix;                   /* prefix for this abrev */
+       struct obj *node;               /* pointer into object table */
+       char *oid;                      /* ASN.1 encoded OID */
+} obj_abrev_list[] = {
+#ifndef NO_ABREV_MIB
+       /* .iso.org.dod.internet.mgmt.mib */
+       { "",   &_mib_obj,              "\53\6\1\2\1" },
+#endif
+#ifndef NO_ABREV_ENTER
+       /* .iso.org.dod.internet.private.enterprises */
+       { "E:", &_enterprises_obj,      "\53\6\1\4\1" },
+#endif
+#ifndef NO_ABREV_EXPERI
+       /* .iso.org.dod.internet.experimental */
+       { "X:", &_experimental_obj,     "\53\6\1\3" },
+#endif
+       { 0,0,0 }
+};
+
+/*
+ * This is used in the OID print routine to walk down the object tree
+ * rooted at `mibroot'.
+ */
+#define OBJ_PRINT(o, suppressdot) \
+{ \
+       if (objp) { \
+               do { \
+                       if ((o) == objp->oid) \
+                               break; \
+               } while (objp = objp->next); \
+       } \
+       if (objp) { \
+               printf(suppressdot?"%s":".%s", objp->desc); \
+               objp = objp->child; \
+       } else \
+               printf(suppressdot?"%u":".%u", (o)); \
+}
+
+/*
+ * This is the definition for the Any-Data-Type storage used purely for
+ * temporary internal representation while decoding an ASN.1 data stream.
+ */
+struct be {
+       unsigned long asnlen;
+       union {
+               caddr_t raw;
+               long integer;
+               unsigned long uns;
+               unsigned char *str;
+       } data;
+       unsigned char form, class, id;          /* tag info */
+       u_char type;
+#define BE_ANY         255
+#define BE_NONE                0
+#define BE_NULL                1
+#define BE_OCTET       2
+#define BE_OID         3
+#define BE_INT         4
+#define BE_UNS         5
+#define BE_STR         6
+#define BE_SEQ         7
+#define BE_INETADDR    8
+#define BE_PDU         9
+};
+
+/*
+ * Defaults for SNMP PDU components
+ */
+#define DEF_COMMUNITY "public"
+#define DEF_VERSION 0
+
+/*
+ * constants for ASN.1 decoding
+ */
+#define OIDMUX 40
+#define ASNLEN_INETADDR 4
+#define ASN_SHIFT7 7
+#define ASN_SHIFT8 8
+#define ASN_BIT8 0x80
+#define ASN_LONGLEN 0x80
+
+#define ASN_ID_BITS 0x1f
+#define ASN_FORM_BITS 0x20
+#define ASN_FORM_SHIFT 5
+#define ASN_CLASS_BITS 0xc0
+#define ASN_CLASS_SHIFT 6
+
+#define ASN_ID_EXT 0x1f                /* extension ID in tag field */
+
+/*
+ * truncated==1 means the packet was complete, but we don't have all of
+ * it to decode.
+ */
+static int truncated;
+#define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
+
+/*
+ * This decodes the next ASN.1 object in the stream pointed to by "p"
+ * (and of real-length "len") and stores the intermediate data in the
+ * provided BE object.
+ *
+ * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
+ * O/w, this returns the number of bytes parsed from "p".
+ */
+int
+asn1_parse(p, len, elem)
+       register u_char *p;
+       int len;
+       struct be *elem;
+{
+       unsigned char form, class, id;
+       int indent=0, i, hdr;
+       char *classstr;
+
+       elem->asnlen = 0;
+       elem->type = BE_ANY;
+       if (len < 1) {
+               ifNotTruncated puts("[nothing to parse], stdout");
+               return -1;
+       }
+
+       /*
+        * it would be nice to use a bit field, but you can't depend on them.
+        *  +---+---+---+---+---+---+---+---+
+        *  + class |frm|        id         |
+        *  +---+---+---+---+---+---+---+---+
+        *    7   6   5   4   3   2   1   0
+        */
+       id = *p & ASN_ID_BITS;          /* lower 5 bits, range 00-1f */
+#ifdef notdef
+       form = (*p & 0xe0) >> 5;        /* move upper 3 bits to lower 3 */
+       class = form >> 1;              /* bits 7&6 -> bits 1&0, range 0-3 */
+       form &= 0x1;                    /* bit 5 -> bit 0, range 0-1 */
+#else
+       form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
+       class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
+#endif
+       elem->form = form;
+       elem->class = class;
+       elem->id = id;
+       if (vflag)
+               printf("|%.2x", *p);
+       p++; len--; hdr = 1;
+       /* extended tag field */
+       if (id == ASN_ID_EXT) {
+               for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
+                       if (vflag)
+                               printf("|%.2x", *p);
+                       id += *p & ~ASN_BIT8;
+               }
+               if (len == 0 && *p & ASN_BIT8) {
+                       ifNotTruncated fputs("[Xtagfield?]", stdout);
+                       return -1;
+               }
+       }
+       if (len < 1) {
+               ifNotTruncated fputs("[no asnlen]", stdout);
+               return -1;
+       }
+       elem->asnlen = *p;
+       if (vflag)
+               printf("|%.2x", *p);
+       p++; len--; hdr++;
+       if (elem->asnlen & ASN_BIT8) {
+               int noct = elem->asnlen % ASN_BIT8;
+               elem->asnlen = 0;
+               if (len < noct) {
+                       ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
+                       return -1;
+               }
+               for (; noct-- > 0; len--, hdr++) {
+                       if (vflag)
+                               printf("|%.2x", *p);
+                       elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
+               }
+       }
+       if (len < elem->asnlen) {
+               if (!truncated) {
+                       printf("[len%d<asnlen%u]", len, elem->asnlen);
+                       return -1;
+               }
+               /* maybe should check at least 4? */
+               elem->asnlen = len;
+       }
+       if (form >= sizeof(Form)/sizeof(Form[0])) {
+               ifNotTruncated printf("[form?%d]", form);
+               return -1;
+       }
+       if (class >= sizeof(Class)/sizeof(Class[0])) {
+               ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
+               return -1;
+       }
+       if (id >= Class[class].numIDs) {
+               ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
+                       Class[class].name, id);
+               return -1;
+       }
+
+       switch (form) {
+       case PRIMITIVE:
+               switch (class) {
+               case UNIVERSAL:
+                       switch (id) {
+                       case STRING:
+                               elem->type = BE_STR;
+                               elem->data.str = p;
+                               break;
+
+                       case INTEGER: {
+                               register long data;
+                               elem->type = BE_INT;
+                               data = 0;
+
+                               if (*p & ASN_BIT8)      /* negative */
+                                       data = -1;
+                               for (i = elem->asnlen; i-- > 0; p++)
+                                       data = (data << ASN_SHIFT8) | *p;
+                               elem->data.integer = data;
+                               break;
+                       }
+
+                       case OBJECTID:
+                               elem->type = BE_OID;
+                               elem->data.raw = (caddr_t)p;
+                               break;
+
+                       case ASN_NULL:
+                               elem->type = BE_NULL;
+                               elem->data.raw = NULL;
+                               break;
+
+                       default:
+                               elem->type = BE_OCTET;
+                               elem->data.raw = (caddr_t)p;
+                               printf("[P/U/%s]",
+                                       Class[class].Id[id]);
+                               break;
+                       }
+                       break;
+
+               case APPLICATION:
+                       switch (id) {
+                       case IPADDR:
+                               elem->type = BE_INETADDR;
+                               elem->data.raw = (caddr_t)p;
+                               break;
+
+                       case COUNTER:
+                       case GAUGE:
+                       case TIMETICKS: {
+                               register unsigned long data;
+                               elem->type = BE_UNS;
+                               data = 0;
+                               for (i = elem->asnlen; i-- > 0; p++)
+                                       data = (data << 8) + *p;
+                               elem->data.uns = data;
+                               break;
+                       }
+
+                       default:
+                               elem->type = BE_OCTET;
+                               elem->data.raw = (caddr_t)p;
+                               printf("[P/A/%s]",
+                                       Class[class].Id[id]);
+                               break;
+                       }
+                       break;
+
+               default:
+                       elem->type = BE_OCTET;
+                       elem->data.raw = (caddr_t)p;
+                       printf("[P/%s/%s]",
+                               Class[class].name, Class[class].Id[id]);
+                       break;
+               }
+               break;
+
+       case CONSTRUCTED:
+               switch (class) {
+               case UNIVERSAL:
+                       switch (id) {
+                       case SEQUENCE:
+                               elem->type = BE_SEQ;
+                               elem->data.raw = (caddr_t)p;
+                               break;
+
+                       default:
+                               elem->type = BE_OCTET;
+                               elem->data.raw = (caddr_t)p;
+                               printf("C/U/%s", Class[class].Id[id]);
+                               break;
+                       }
+                       break;
+
+               case CONTEXT:
+                       elem->type = BE_PDU;
+                       elem->data.raw = (caddr_t)p;
+                       break;
+
+               default:
+                       elem->type = BE_OCTET;
+                       elem->data.raw = (caddr_t)p;
+                       printf("C/%s/%s",
+                               Class[class].name, Class[class].Id[id]);
+                       break;
+               }
+               break;
+       }
+       p += elem->asnlen;
+       len -= elem->asnlen;
+       return elem->asnlen + hdr;
+}
+
+/*
+ * Display the ASN.1 object represented by the BE object.
+ * This used to be an integral part of asn1_parse() before the intermediate
+ * BE form was added.
+ */
+void
+asn1_print(elem)
+       struct be *elem;
+{
+       u_char *p = (u_char *)elem->data.raw;
+       u_long asnlen = elem->asnlen;
+       int i;
+
+       switch (elem->type) {
+
+       case BE_OCTET:
+               for (i = asnlen; i-- > 0; p++);
+                       printf("_%.2x", *p);
+               break;
+
+       case BE_NULL:
+               break;
+
+       case BE_OID: {
+       int o = 0, first = -1, i = asnlen;
+
+               if (!nflag && asnlen > 2) {
+                       struct obj_abrev *a = &obj_abrev_list[0];
+                       for (; a->node; a++) {
+                               if (!memcmp(a->oid, p, strlen(a->oid))) {
+                                       objp = a->node->child;
+                                       i -= strlen(a->oid);
+                                       p += strlen(a->oid);
+                                       fputs(a->prefix, stdout);
+                                       first = 1;
+                                       break;
+                               }
+                       }
+               }
+               for (; i-- > 0; p++) {
+                       o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
+                       if (*p & ASN_LONGLEN)
+                               continue;
+
+                       /*
+                        * first subitem encodes two items with 1st*OIDMUX+2nd
+                        */
+                       if (first < 0) {
+                               if (!nflag)
+                                       objp = mibroot;
+                               first = 0;
+                               OBJ_PRINT(o/OIDMUX, first);
+                               o %= OIDMUX;
+                       }
+                       OBJ_PRINT(o, first);
+                       if (--first < 0)
+                               first = 0;
+                       o = 0;
+               }
+               break;
+       }
+
+       case BE_INT:
+               printf("%ld", elem->data.integer);
+               break;
+
+       case BE_UNS:
+               printf("%ld", elem->data.uns);
+               break;
+
+       case BE_STR: {
+               register int printable = 1, first = 1;
+               u_char *p = elem->data.str;
+               for (i = asnlen; printable && i-- > 0; p++)
+                       printable = isprint(*p) || isspace(*p);
+               p = elem->data.str;
+               if (printable)
+                       (void)printfn(p, p+asnlen);
+               else
+                       for (i = asnlen; i-- > 0; p++) {
+                               printf(first ? "%.2x" : "_%.2x", *p);
+                               first = 0;
+                       }
+               break;
+       }
+
+       case BE_SEQ:
+               printf("Seq(%d)", elem->asnlen);
+               break;
+
+       case BE_INETADDR: {
+               char sep;
+               if (asnlen != ASNLEN_INETADDR)
+                       printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
+               sep='[';
+               for (i = asnlen; i-- > 0; p++) {
+                       printf("%c%u", sep, *p);
+                       sep='.';
+               }
+               putchar(']');
+               break;
+       }
+
+       case BE_PDU:
+               printf("%s(%d)",
+                       Class[CONTEXT].Id[elem->id], elem->asnlen);
+               break;
+
+       case BE_ANY:
+               fputs("[BE_ANY!?]", stdout);
+               break;
+
+       default:
+               fputs("[be!?]", stdout);
+               break;
+       }
+}
+
+#ifdef notdef
+/*
+ * This is a brute force ASN.1 printer: recurses to dump an entire structure.
+ * This will work for any ASN.1 stream, not just an SNMP PDU.
+ *
+ * By adding newlines and spaces at the correct places, this would print in
+ * Rose-Normal-Form.
+ *
+ * This is not currently used.
+ */
+void
+asn1_decode(p, length)
+       u_char *p;
+       int length;
+{
+       struct be elem;
+       int i = 0;
+
+       while (i >= 0 && length > 0) {
+               i = asn1_parse(p, length, &elem);
+               if (i >= 0) {
+                       fputs(" ", stdout);
+                       asn1_print(&elem);
+                       if (elem.type == BE_SEQ || elem.type == BE_PDU) {
+                               fputs(" {", stdout);
+                               asn1_decode(elem.data.raw, elem.asnlen);
+                               fputs(" }", stdout);
+                       }
+                       length -= i;
+                       p += i;
+               }
+       }
+}
+#endif
+
+/*
+ * General SNMP header
+ *     SEQUENCE {
+ *             version INTEGER {version-1(0)},
+ *             community OCTET STRING,
+ *             data ANY        -- PDUs
+ *     }
+ * PDUs for all but Trap: (see rfc1157 from page 15 on)
+ *     SEQUENCE {
+ *             request-id INTEGER,
+ *             error-status INTEGER,
+ *             error-index INTEGER,
+ *             varbindlist SEQUENCE OF
+ *                     SEQUENCE {
+ *                             name ObjectName,
+ *                             value ObjectValue
+ *                     }
+ *     }
+ * PDU for Trap:
+ *     SEQUENCE {
+ *             enterprise OBJECT IDENTIFIER,
+ *             agent-addr NetworkAddress,
+ *             generic-trap INTEGER,
+ *             specific-trap INTEGER,
+ *             time-stamp TimeTicks,
+ *             varbindlist SEQUENCE OF
+ *                     SEQUENCE {
+ *                             name ObjectName,
+ *                             value ObjectValue
+ *                     }
+ *     }
+ */
+
+/*
+ * Decode SNMP varBind
+ */
+void
+varbind_print (pduid, np, length, error)
+       u_char pduid, *np;
+       int length, error;
+{
+       struct be elem;
+       int count = 0, index;
+
+       /* Sequence of varBind */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_SEQ) {
+               fputs("[!SEQ of varbind]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       if (count < length)
+               printf("[%d extra after SEQ of varbind]", length - count);
+       /* descend */
+       length = elem.asnlen;
+       np = (u_char *)elem.data.raw;
+
+       for (index = 1; length > 0; index++) {
+               u_char *vbend;
+               int vblength;
+
+               if (!error || index == error)
+                       fputs(" ", stdout);
+
+               /* Sequence */
+               if ((count = asn1_parse(np, length, &elem)) < 0)
+                       return;
+               if (elem.type != BE_SEQ) {
+                       fputs("[!varbind]", stdout);
+                       asn1_print(&elem);
+                       return;
+               }
+               vbend = np + count;
+               vblength = length - count;
+               /* descend */
+               length = elem.asnlen;
+               np = (u_char *)elem.data.raw;
+
+               /* objName (OID) */
+               if ((count = asn1_parse(np, length, &elem)) < 0)
+                       return;
+               if (elem.type != BE_OID) {
+                       fputs("[objName!=OID]", stdout);
+                       asn1_print(&elem);
+                       return;
+               }
+               if (!error || index == error)
+                       asn1_print(&elem);
+               length -= count;
+               np += count;
+
+               if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
+                               fputs("=", stdout);
+
+               /* objVal (ANY) */
+               if ((count = asn1_parse(np, length, &elem)) < 0)
+                       return;
+               if (pduid == GETREQ || pduid == GETNEXTREQ) {
+                       if (elem.type != BE_NULL) {
+                               fputs("[objVal!=NULL]", stdout);
+                               asn1_print(&elem);
+                       }
+               } else
+                       if (error && index == error && elem.type != BE_NULL)
+                               fputs("[err objVal!=NULL]", stdout);
+                       if (!error || index == error)
+                               asn1_print(&elem);
+
+               length = vblength;
+               np = vbend;
+       }
+}
+
+/*
+ * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
+ */
+void
+snmppdu_print (pduid, np, length)
+       u_char pduid, *np;
+       int length;
+{
+       struct be elem;
+       int count = 0, error;
+
+       /* reqId (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[reqId!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       /* ignore the reqId */
+       length -= count;
+       np += count;
+
+       /* errorStatus (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[errorStatus!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       error = 0;
+       if ((pduid == GETREQ || pduid == GETNEXTREQ)
+           && elem.data.integer != 0) {
+               char errbuf[10];
+               printf("[errorStatus(%s)!=0]", 
+                       DECODE_ErrorStatus(elem.data.integer));
+       } else if (elem.data.integer != 0) {
+               char errbuf[10];
+               printf(" %s", DECODE_ErrorStatus(elem.data.integer));
+               error = elem.data.integer;
+       }
+       length -= count;
+       np += count;
+
+       /* errorIndex (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[errorIndex!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       if ((pduid == GETREQ || pduid == GETNEXTREQ)
+           && elem.data.integer != 0)
+               printf("[errorIndex(%d)!=0]", elem.data.integer);
+       else if (elem.data.integer != 0) {
+               if (!error)
+                       printf("[errorIndex(%d) w/o errorStatus]",
+                               elem.data.integer);
+               else {
+                       printf("@%d", elem.data.integer);
+                       error = elem.data.integer;
+               }
+       } else if (error) {
+               fputs("[errorIndex==0]", stdout);
+               error = 0;
+       }
+       length -= count;
+       np += count;
+
+       varbind_print(pduid, np, length, error);
+       return;
+}
+
+/*
+ * Decode SNMP Trap PDU
+ */
+void
+trap_print (np, length)
+       u_char *np;
+       int length;
+{
+       struct be elem;
+       int count = 0, generic;
+
+       putchar(' ');
+
+       /* enterprise (oid) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_OID) {
+               fputs("[enterprise!=OID]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       asn1_print(&elem);
+       length -= count;
+       np += count;
+
+       putchar(' ');
+
+       /* agent-addr (inetaddr) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INETADDR) {
+               fputs("[agent-addr!=INETADDR]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       asn1_print(&elem);
+       length -= count;
+       np += count;
+
+       /* generic-trap (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[generic-trap!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       generic = elem.data.integer;
+       {
+               char buf[10];
+               printf(" %s", DECODE_GenericTrap(generic));
+       }
+       length -= count;
+       np += count;
+
+       /* specific-trap (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[specific-trap!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       if (generic != GT_ENTERPRISE) {
+               if (elem.data.integer != 0)
+                       printf("[specific-trap(%d)!=0]", elem.data.integer);
+       } else
+               printf(" s=%d", elem.data.integer);
+       length -= count;
+       np += count;
+
+       putchar(' ');
+
+       /* time-stamp (TimeTicks) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_UNS) {                      /* XXX */
+               fputs("[time-stamp!=TIMETICKS]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       asn1_print(&elem);
+       length -= count;
+       np += count;
+
+       varbind_print (TRAP, np, length, 0);
+       return;
+}
+
+/*
+ * Decode SNMP header and pass on to PDU printing routines
+ */
+void
+snmp_print (np, length)
+       u_char *np;
+       int length;
+{
+       struct be elem, pdu;
+       int count = 0;
+
+       truncated = 0;
+
+       /* truncated packet? */
+       if (np + length > snapend) {
+               truncated = 1;
+               length = snapend - np;
+       }
+
+       putchar(' ');
+
+       /* initial Sequence */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_SEQ) {
+               fputs("[!init SEQ]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       if (count < length)
+               printf("[%d extra after iSEQ]", length - count);
+       /* descend */
+       length = elem.asnlen;
+       np = (u_char *)elem.data.raw;
+       /* Version (Integer) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_INT) {
+               fputs("[version!=INT]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       /* only handle version==0 */
+       if (elem.data.integer != DEF_VERSION) {
+               printf("[version(%d)!=0]", elem.data.integer);
+               return;
+       }
+       length -= count;
+       np += count;
+
+       /* Community (String) */
+       if ((count = asn1_parse(np, length, &elem)) < 0)
+               return;
+       if (elem.type != BE_STR) {
+               fputs("[comm!=STR]", stdout);
+               asn1_print(&elem);
+               return;
+       }
+       /* default community */
+       if (strncmp(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1))
+               /* ! "public" */
+               printf("C=%.*s ", elem.asnlen, elem.data.str);
+       length -= count;
+       np += count;
+
+       /* PDU (Context) */
+       if ((count = asn1_parse(np, length, &pdu)) < 0)
+               return;
+       if (pdu.type != BE_PDU) {
+               fputs("[no PDU]", stdout);
+               return;
+       }
+       if (count < length)
+               printf("[%d extra after PDU]", length - count);
+       asn1_print(&pdu);
+       /* descend into PDU */
+       length = pdu.asnlen;
+       np = (u_char *)pdu.data.raw;
+
+       switch (pdu.id) {
+       case TRAP:
+               trap_print(np, length);
+               break;
+       case GETREQ:
+       case GETNEXTREQ:
+       case GETRESP:
+       case SETREQ:
+               snmppdu_print(pdu.id, np, length);
+               break;
+       }
+       return;
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-sunrpc.c b/usr/src/contrib/tcpdump/tcpdump/print-sunrpc.c
new file mode 100644 (file)
index 0000000..ad28e93
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1992 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-sunrpc.c,v 1.1 92/06/02 11:36:37 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <sys/time.h>
+#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/svc.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_msg.h>
+
+#include <rpc/pmap_prot.h>
+
+#include <ctype.h>
+
+#include "interface.h"
+
+#include "addrtoname.h"
+#include "extract.h"
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Byte swap an array of n words.
+ * Assume input is word-aligned.
+ * Check that buffer is bounded by "snapend".
+ */
+static void
+bswap(bp, n)
+       register u_long *bp;
+       register u_int n;
+{
+       register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp);
+
+       if (nwords > n)
+               nwords = n;
+       for (; --nwords >= 0; ++bp)
+               *bp = ntohl(*bp);
+}
+#endif
+
+void
+sunrpcrequest_print(rp, length, ip)
+       register struct rpc_msg *rp;
+       int length;
+       register struct ip *ip;
+{
+       register u_long *dp;
+       register u_char *ep = snapend;
+#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+       bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+
+       if (!nflag)
+               (void)printf("%s.%x > %s.sunrpc: %d",
+                            ipaddr_string(&ip->ip_src),
+                            rp->rm_xid,
+                            ipaddr_string(&ip->ip_dst),
+                            length);
+       else
+               (void)printf("%s.%x > %s.%x: %d",
+                            ipaddr_string(&ip->ip_src),
+                            rp->rm_xid,
+                            ipaddr_string(&ip->ip_dst),
+                            PMAPPORT,
+                            length);
+
+       switch (rp->rm_call.cb_proc) {
+
+       case PMAPPROC_NULL:
+               printf(" null");
+               break;
+
+       case PMAPPROC_SET:
+               printf(" set");
+               break;
+
+       case PMAPPROC_UNSET:
+               printf(" unset");
+               break;
+
+       case PMAPPROC_GETPORT:
+               printf(" getport");
+               break;
+
+       case PMAPPROC_DUMP:
+               printf(" dump");
+               break;
+
+       case PMAPPROC_CALLIT:
+               printf(" callit");
+               break;
+
+       default:
+               printf(" proc #%d", rp->rm_call.cb_proc);
+       }
+       printf(" prog #%d", rp->rm_call.cb_prog);
+       putchar('\n');
+}
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-tcp.c b/usr/src/contrib/tcpdump/tcpdump/print-tcp.c
new file mode 100644 (file)
index 0000000..9974b3c
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-tcp.c,v 1.18 92/05/25 14:29:04 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#ifdef X10
+#include <X/X.h>
+#include <X/Xproto.h>
+#endif
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#ifndef TCPOPT_WSCALE
+#define        TCPOPT_WSCALE           3       /* window scale factor (rfc1072) */
+#endif
+#ifndef TCPOPT_SACKOK
+#define        TCPOPT_SACKOK           4       /* selective ack ok (rfc1072) */
+#endif
+#ifndef TCPOPT_SACK
+#define        TCPOPT_SACK             5       /* selective ack (rfc1072) */
+#endif
+#ifndef TCPOPT_ECHO
+#define        TCPOPT_ECHO             6       /* echo (rfc1072) */
+#endif
+#ifndef TCPOPT_ECHOREPLY
+#define        TCPOPT_ECHOREPLY        7       /* echo (rfc1072) */
+#endif
+
+struct tha {
+       struct in_addr src;
+       struct in_addr dst;
+       u_int port;
+};
+
+struct tcp_seq_hash {
+       struct tcp_seq_hash *nxt;
+       struct tha addr;
+       tcp_seq seq;
+       tcp_seq ack;
+};
+
+#define TSEQ_HASHSIZE 919
+
+static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
+
+
+void
+tcp_print(tp, length, ip)
+       register struct tcphdr *tp;
+       register int length;
+       register struct ip *ip;
+{
+       register u_char flags;
+       register int hlen;
+
+       if ((u_char *)(tp + 1)  > snapend) {
+               printf("[|tcp]");
+               return;
+       }
+       if (length < sizeof(struct tcphdr)) {
+               (void)printf("truncated-tcp %d", length);
+               return;
+       }
+
+       NTOHS(tp->th_sport);
+       NTOHS(tp->th_dport);
+       NTOHL(tp->th_seq);
+       NTOHL(tp->th_ack);
+       NTOHS(tp->th_win);
+       NTOHS(tp->th_urp);
+
+       (void)printf("%s.%s > %s.%s: ",
+               ipaddr_string(&ip->ip_src), tcpport_string(tp->th_sport),
+               ipaddr_string(&ip->ip_dst), tcpport_string(tp->th_dport));
+
+       if (!qflag) {
+#ifdef X10
+               register int be;
+
+               if ((be = (tp->th_sport == X_TCP_BI_PORT ||
+                   tp->th_dport == X_TCP_BI_PORT)) ||
+                   tp->th_sport == X_TCP_LI_PORT ||
+                   tp->th_dport == X_TCP_LI_PORT) {
+                       register XReq *xp = (XReq *)(tp + 1);
+
+                       x10_print(xp, length - sizeof(struct tcphdr), be);
+                       return;
+               }
+#endif
+       }
+
+       if (qflag) {
+               (void)printf("tcp %d", length - tp->th_off * 4);
+               return;
+       }
+       if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
+               if (flags & TH_SYN)
+                       putchar('S');
+               if (flags & TH_FIN)
+                       putchar('F');
+               if (flags & TH_RST)
+                       putchar('R');
+               if (flags & TH_PUSH)
+                       putchar('P');
+       } else
+               putchar('.');
+
+       if (!Sflag && (flags & TH_ACK)) {
+               register struct tcp_seq_hash *th;
+               register int rev;
+               struct tha tha;
+               /*
+                * Find (or record) the initial sequence numbers for
+                * this conversation.  (we pick an arbitrary
+                * collating order so there's only one entry for
+                * both directions).
+                */
+               if (tp->th_sport < tp->th_dport ||
+                   (tp->th_sport == tp->th_dport &&
+                    ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
+                       tha.src = ip->ip_src, tha.dst = ip->ip_dst;
+                       tha.port = tp->th_sport << 16 | tp->th_dport;
+                       rev = 0;
+               } else {
+                       tha.src = ip->ip_dst, tha.dst = ip->ip_src;
+                       tha.port = tp->th_dport << 16 | tp->th_sport;
+                       rev = 1;
+               }
+
+               for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
+                    th->nxt; th = th->nxt)
+                       if (!bcmp((char *)&tha, (char *)&th->addr,
+                                 sizeof(th->addr)))
+                               break;
+
+               if (!th->nxt || flags & TH_SYN) {
+                       /* didn't find it or new conversation */
+                       if (!th->nxt)
+                               th->nxt = (struct tcp_seq_hash *)
+                                       calloc(1, sizeof (*th));
+                       th->addr = tha;
+                       if (rev)
+                               th->ack = tp->th_seq, th->seq = tp->th_ack - 1;
+                       else
+                               th->seq = tp->th_seq, th->ack = tp->th_ack - 1;
+               } else {
+                       if (rev)
+                               tp->th_seq -= th->ack, tp->th_ack -= th->seq;
+                       else
+                               tp->th_seq -= th->seq, tp->th_ack -= th->ack;
+               }
+       }
+       hlen = tp->th_off * 4;
+       length -= hlen;
+       if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
+               (void)printf(" %lu:%lu(%d)", tp->th_seq, tp->th_seq + length, 
+                            length);
+       if (flags & TH_ACK)
+               (void)printf(" ack %lu", tp->th_ack);
+
+       (void)printf(" win %d", tp->th_win);
+
+       if (flags & TH_URG)
+               (void)printf(" urg %d", tp->th_urp);
+       /*
+        * Handle any options.
+        */
+       if ((hlen -= sizeof(struct tcphdr)) > 0) {
+               register u_char *cp = (u_char *)tp + sizeof(struct tcphdr);
+               int i;
+               char ch = '<';
+
+               putchar(' ');
+               while (--hlen >= 0) {
+                       putchar(ch);
+                       switch (*cp++) {
+                       case TCPOPT_MAXSEG:
+                       {
+                               u_short mss;
+#ifdef TCPDUMP_ALIGN
+                               bcopy((char *)cp + 1, (char *)&mss, 
+                                     sizeof(mss));
+#else
+                               mss = *(u_short *)(cp + 1);
+#endif                         
+                               (void)printf("mss %d", ntohs(mss));
+                               if (*cp != 4)
+                                       (void)printf("[len %d]", *cp);
+                               cp += 3;
+                               hlen -= 3;
+                               break;
+                       }
+                       case TCPOPT_EOL:
+                               (void)printf("eol");
+                               break;
+                       case TCPOPT_NOP:
+                               (void)printf("nop");
+                               break;
+                       case TCPOPT_WSCALE:
+                               (void)printf("wscale %d", cp[1]);
+                               if (*cp != 3)
+                                       (void)printf("[len %d]", *cp);
+                               cp += 2;
+                               hlen -= 2;
+                               break;
+                       case TCPOPT_SACKOK:
+                               (void)printf("sackOK");
+                               if (*cp != 2)
+                                       (void)printf("[len %d]", *cp);
+                               cp += 1;
+                               hlen -= 1;
+                               break;
+                       case TCPOPT_ECHO:
+                       {
+                               u_long v;
+#ifdef TCPDUMP_ALIGN
+                               bcopy((char *)cp + 1, (char *)&v, 
+                                     sizeof(v));
+#else
+                               v = *(u_long *)(cp + 1);
+#endif                         
+                               (void)printf("echo %lu", v);
+                               if (*cp != 6)
+                                       (void)printf("[len %d]", *cp);
+                               cp += 5;
+                               hlen -= 5;
+                               break;
+                       }
+                       case TCPOPT_ECHOREPLY:
+                       {
+                               u_long v;
+#ifdef TCPDUMP_ALIGN
+                               bcopy((char *)cp + 1, (char *)&v, 
+                                     sizeof(v));
+#else
+                               v = *(u_long *)(cp + 1);
+#endif                         
+                               (void)printf("echoreply %lu", v);
+                               if (*cp != 6)
+                                       (void)printf("[len %d]", *cp);
+                               cp += 5;
+                               hlen -= 5;
+                               break;
+                       }
+                       default:
+                               (void)printf("opt-%d:", cp[-1]);
+                               for (i = *cp++ - 2, hlen -= i + 1; i > 0; --i)
+                                       (void)printf("%02x", *cp++);
+                               break;
+                       }
+                       ch = ',';
+               }
+               putchar('>');
+       }
+}
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-tftp.c b/usr/src/contrib/tcpdump/tcpdump/print-tftp.c
new file mode 100644 (file)
index 0000000..3f8f079
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print trivial file transfer protocol packets.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-tftp.c,v 1.13 91/04/19 10:46:57 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <arpa/tftp.h>
+
+#include "interface.h"
+#include <strings.h>
+#include <ctype.h>
+
+struct int2str {
+       int code;
+       char *str;
+};
+
+/* op code to string mapping */
+static struct int2str op2str[] = {
+       RRQ, "RRQ",                     /* read request */
+       WRQ, "WRQ",                     /* write request */
+       DATA, "DATA",                   /* data packet */
+       ACK, "ACK",                     /* acknowledgement */
+       ERROR, "ERROR",                 /* error code */
+       0, 0
+};
+
+/* error code to string mapping */
+static struct int2str err2str[] = {
+       EUNDEF, "EUNDEF",               /* not defined */
+       ENOTFOUND, "ENOTFOUND",         /* file not found */
+       EACCESS, "EACCESS",             /* access violation */
+       ENOSPACE, "ENOSPACE",           /* disk full or allocation exceeded *?
+       EBADOP, "EBADOP",               /* illegal TFTP operation */
+       EBADID, "EBADID",               /* unknown transfer ID */
+       EEXISTS, "EEXISTS",             /* file already exists */
+       ENOUSER, "ENOUSER",             /* no such user */
+       0, 0
+};
+
+/*
+ * Print trivial file transfer program requests
+ */
+void
+tftp_print(tp, length)
+       register struct tftphdr *tp;
+       int length;
+{
+       register struct int2str *ts;
+       register u_char *ep;
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+       static char tstr[] = " [|tftp]";
+
+       /* 'ep' points to the end of avaible data. */
+       ep = (u_char *)snapend;
+
+       /* Print length */
+       printf(" %d", length);
+
+       /* Print tftp request type */
+       TCHECK(tp->th_opcode, sizeof(tp->th_opcode));
+       NTOHS(tp->th_opcode);
+       putchar(' ');
+       for (ts = op2str; ts->str; ++ts)
+               if (ts->code == tp->th_opcode) {
+                       fputs(ts->str, stdout);
+                       break;
+               }
+       if (ts->str == 0) {
+               /* Bail if bogus opcode */
+               printf("tftp-#%d", tp->th_opcode);
+               return;
+       }
+
+       switch (tp->th_opcode) {
+
+       case RRQ:
+       case WRQ:
+               putchar(' ');
+               if (printfn((u_char *)tp->th_stuff, ep)) {
+                       fputs(&tstr[1], stdout);
+                       return;
+               }
+               break;
+
+       case DATA:
+               TCHECK(tp->th_block, sizeof(tp->th_block));
+               NTOHS(tp->th_block);
+               printf(" block %d", tp->th_block);
+               break;
+
+       case ACK:
+               break;
+
+       case ERROR:
+               /* Print error code string */
+               TCHECK(tp->th_code, sizeof(tp->th_code));
+               NTOHS(tp->th_code);
+               putchar(' ');
+               for (ts = err2str; ts->str; ++ts)
+                       if (ts->code == tp->th_code) {
+                               fputs(ts->str, stdout);
+                               break;
+                       }
+               if (ts->str == 0)
+                       printf("tftp-err-#%d", tp->th_code);
+
+               /* Print error message string */
+               putchar(' ');
+               if (printfn((u_char *)tp->th_data, ep)) {
+                       fputs(&tstr[1], stdout);
+                       return;
+               }
+               break;
+
+       default:
+               /* We shouldn't get here */
+               printf("(unknown #%d)", tp->th_opcode);
+               break;
+       }
+       return;
+trunc:
+       fputs(tstr, stdout);
+#undef TCHECK
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/print-udp.c b/usr/src/contrib/tcpdump/tcpdump/print-udp.c
new file mode 100644 (file)
index 0000000..cd51808
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: print-udp.c,v 1.26 92/05/22 19:43:17 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/nameser.h>
+#include <arpa/tftp.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/svc.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_msg.h>
+
+#include "interface.h"
+/* These must come after interface.h for BSD. */
+#if BSD >= 199006
+#include <sys/ucred.h>
+#include <nfs/nfsv2.h>
+#endif
+#include <nfs/nfs.h>
+
+#include "addrtoname.h"
+#include "appletalk.h"
+
+#include "bootp.h"
+
+/* XXX probably should use getservbyname() and cache answers */
+#define TFTP_PORT 69           /*XXX*/
+#define SUNRPC_PORT 111                /*XXX*/
+#define SNMP_PORT 161          /*XXX*/
+#define NTP_PORT 123           /*XXX*/
+#define SNMPTRAP_PORT 162      /*XXX*/
+#define RIP_PORT 520           /*XXX*/
+
+void
+udp_print(up, length, ip)
+       register struct udphdr *up;
+       int length;
+       register struct ip *ip;
+{
+       register u_char  *cp = (u_char *)(up + 1);
+
+       if (cp > snapend) {
+               printf("[|udp]");
+               return;
+       }
+       if (length < sizeof(struct udphdr)) {
+               (void)printf(" truncated-udp %d", length);
+               return;
+       }
+       length -= sizeof(struct udphdr);
+
+       NTOHS(up->uh_sport);
+       NTOHS(up->uh_dport);
+       NTOHS(up->uh_ulen);
+
+       if (! qflag) {
+               register struct rpc_msg *rp;
+               enum msg_type direction;
+
+               rp = (struct rpc_msg *)(up + 1);
+               direction = (enum msg_type)ntohl(rp->rm_direction);
+               if (up->uh_dport == NFS_PORT && direction == CALL) {
+                       nfsreq_print(rp, length, ip);
+                       return;
+               }
+               else if (up->uh_sport == NFS_PORT && direction == REPLY) {
+                       nfsreply_print(rp, length, ip);
+                       return;
+               }
+#ifdef notdef
+               else if (up->uh_dport == SUNRPC_PORT && direction == CALL) {
+                       sunrpcrequest_print(rp, length, ip);
+                       return;
+               }
+#endif
+               else if (cp[2] == 2 && (atalk_port(up->uh_sport) ||
+                        atalk_port(up->uh_dport))) {
+                       ddp_print((struct atDDP *)(&cp[3]), length - 3);
+                       return;
+               }
+       }
+       (void)printf("%s.%s > %s.%s:",
+               ipaddr_string(&ip->ip_src), udpport_string(up->uh_sport),
+               ipaddr_string(&ip->ip_dst), udpport_string(up->uh_dport));
+
+       if (!qflag) {
+#define ISPORT(p) (up->uh_dport == (p) || up->uh_sport == (p))
+               if (ISPORT(NAMESERVER_PORT))
+                       ns_print((HEADER *)(up + 1), length);
+               else if (ISPORT(TFTP_PORT))
+                       tftp_print((struct tftphdr *)(up + 1), length);
+               else if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS))
+                       bootp_print((struct bootp *)(up + 1), length,
+                           up->uh_sport, up->uh_dport);
+               else if (up->uh_dport == RIP_PORT)
+                       rip_print((u_char *)(up + 1), length);
+               else if (ISPORT(SNMP_PORT) || ISPORT(SNMPTRAP_PORT))
+                       snmp_print((u_char *)(up + 1), length);
+               else if (ISPORT(NTP_PORT))
+                       ntp_print((struct ntpdata *)(up + 1), length);
+               else
+                       (void)printf(" udp %d", up->uh_ulen - sizeof(*up));
+#undef ISPORT
+       } else
+               (void)printf(" udp %d", up->uh_ulen - sizeof(*up));
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/savefile.c b/usr/src/contrib/tcpdump/tcpdump/savefile.c
new file mode 100644 (file)
index 0000000..79bb9e8
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1990,1991 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#)$Header: savefile.c,v 1.27 92/01/26 21:29:26 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * savefile.c - supports offline use of tcpdump
+ *     Extraction/creation by Jeffrey Mogul, DECWRL
+ *     Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "version.h"
+#include "savefile.h"
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are longs so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ */
+struct file_header {
+       u_long magic;
+       u_short version_major;
+       u_short version_minor;
+       long thiszone;          /* gmt to local correction */
+       u_long sigfigs;         /* accuracy of timestamps */
+       u_long snaplen;         /* max length saved portion of each pkt */
+       u_long linktype;
+};
+
+int sf_swapped;
+
+FILE *sf_readfile;
+FILE *sf_writefile;
+
+static int
+sf_write_header(fp, linktype, thiszone, snaplen, precision)
+       FILE *fp;
+       int linktype;
+       int thiszone;
+       int snaplen;
+       int precision;
+{
+       struct file_header hdr;
+
+       hdr.magic = TCPDUMP_MAGIC;
+       hdr.version_major = VERSION_MAJOR;
+       hdr.version_minor = VERSION_MINOR;
+
+       hdr.thiszone = thiszone;
+       hdr.snaplen = snaplen;
+       hdr.sigfigs = precision;
+       hdr.linktype = linktype;
+
+       if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
+               return -1;
+
+       return 0;
+}
+
+static void
+swap_hdr(hp)
+       struct file_header *hp;
+{
+       hp->version_major = SWAPSHORT(hp->version_major);
+       hp->version_minor = SWAPSHORT(hp->version_minor);
+       hp->thiszone = SWAPLONG(hp->thiszone);
+       hp->sigfigs = SWAPLONG(hp->sigfigs);
+       hp->snaplen = SWAPLONG(hp->snaplen);
+       hp->linktype = SWAPLONG(hp->linktype);
+}
+
+int
+sf_read_init(fname, linktypep, thiszonep, snaplenp, precision)
+       char *fname;
+       int *linktypep, *thiszonep, *snaplenp, *precision;
+{
+       register FILE *fp;
+       struct file_header hdr;
+
+       if (fname[0] == '-' && fname[1] == '\0')
+               fp = stdin;
+       else {
+               fp = fopen(fname, "r");
+               if (fp == 0) {
+                       (void) fprintf(stderr, "tcpdump: fopen: ");
+                       perror(fname);
+                       exit(1);
+               }
+       }
+       if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
+               (void) fprintf(stderr, "tcpdump: fread: ");
+               perror(fname);
+               exit(1);
+       }
+       if (hdr.magic != TCPDUMP_MAGIC) {
+               if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC)
+                       return SFERR_BADF;
+               sf_swapped = 1;
+               swap_hdr(&hdr);
+       }
+       if (hdr.version_major < VERSION_MAJOR)
+               return SFERR_BADVERSION;
+
+       *thiszonep = hdr.thiszone;
+       *snaplenp = hdr.snaplen;
+       *linktypep = hdr.linktype;
+       *precision = hdr.sigfigs;
+
+       sf_readfile = fp;
+
+       return 0;
+}
+
+/*
+ * Print out packets stored in the file initilized by sf_read_init().
+ * If cnt >= 0, return after 'cnt' packets, otherwise continue until eof.
+ */
+int
+sf_read(filtp, cnt, snaplen, printit)
+       struct bpf_program *filtp;
+       int cnt, snaplen;
+       void (*printit)();
+{
+       struct packet_header h;
+       u_char *buf;
+       struct bpf_insn *fcode = filtp->bf_insns;
+       int status = 0;
+
+       buf = (u_char *)malloc(snaplen);
+
+       while (status == 0) {
+               status = sf_next_packet(&h, buf, snaplen);
+
+               if (status)
+                       break;
+               /*
+                * XXX It's possible (and likely) for us to screw up the
+                * network layer alignment when we pass down packets from 
+                * this point (ip_print deals by copying the ip header
+                * to an aligned buffer).  There doesn't seem to be a 
+                * clean way to fix this.  We could compute an offset 
+                * from the link type (which would have to be passed in),
+                * but that only works for fixed size headers.
+                */
+               if (bpf_filter(fcode, buf, h.len, h.caplen)) {
+                       if (cnt >= 0 && --cnt < 0)
+                               break;
+                       (*printit)(buf, &h.ts, h.len, h.caplen);
+               }
+       }
+
+       if (status == SFERR_EOF)
+               /* treat EOF's as okay status */
+               status = 0;
+
+       free((char *)buf);
+       return status;
+}
+
+/*
+ * Read sf_readfile and return the next packet.  Return the header in hdr 
+ * and the contents in buf.  Return 0 on success, SFERR_EOF if there were 
+ * no more packets, and SFERR_TRUNC if a partial packet was encountered.
+ */
+int
+sf_next_packet(hdr, buf, buflen)
+       struct packet_header *hdr;
+       u_char *buf;
+       int buflen;
+{
+       FILE *fp = sf_readfile;
+
+       /* read the stamp */
+       if (fread((char *)hdr, sizeof(struct packet_header), 1, fp) != 1) {
+               /* probably an EOF, though could be a truncated packet */
+               return SFERR_EOF;
+       }
+
+       if (sf_swapped) {
+               /* these were written in opposite byte order */
+               hdr->caplen = SWAPLONG(hdr->caplen);
+               hdr->len = SWAPLONG(hdr->len);
+               hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
+               hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
+       }
+
+       if (hdr->caplen > buflen)
+               return SFERR_BADF;
+
+       /* read the packet itself */
+
+       if (fread((char *)buf, hdr->caplen, 1, fp) != 1)
+               return SFERR_TRUNC;
+
+       return 0;
+}
+
+/*
+ * Initialize so that sf_write() will output to the file named 'fname'.
+ */
+void
+sf_write_init(fname, linktype, thiszone, snaplen, precision)
+       char *fname;
+       int linktype;
+       int thiszone;
+       int snaplen;
+       int precision;
+{
+       if (fname[0] == '-' && fname[1] == '\0')
+               sf_writefile = stdout;
+       else {
+               sf_writefile = fopen(fname, "w");
+               if (sf_writefile == 0) {
+                       (void) fprintf(stderr, "tcpdump: fopen: ");
+                       perror(fname);
+                       exit(1);
+               }
+       }
+       (void)sf_write_header(sf_writefile,
+           linktype, thiszone, snaplen, precision);
+}
+
+/*
+ * Output a packet to the intialized dump file.
+ */
+void
+sf_write(sp, tvp, length, caplen)
+       u_char *sp;
+       struct timeval *tvp;
+       int length;
+       int caplen;
+{
+       struct packet_header h;
+
+       h.ts.tv_sec = tvp->tv_sec;
+       h.ts.tv_usec = tvp->tv_usec;
+       h.len = length;
+       h.caplen = caplen;
+
+       (void)fwrite((char *)&h, sizeof h, 1, sf_writefile);
+       (void)fwrite((char *)sp, caplen, 1, sf_writefile);
+}
+
+void
+sf_err(code)
+       int code;
+{
+       switch (code) {
+       case SFERR_BADVERSION:
+               error("archaic file format");
+               /* NOTREACHED */
+
+       case SFERR_BADF:
+               error("bad dump file format");
+               /* NOTREACHED */
+
+       case SFERR_TRUNC:
+               error("truncated dump file");
+               /* NOTREACHED */
+
+       case SFERR_EOF:
+               error("EOF reading dump file");
+               /* NOTREACHED */
+
+       default:
+               error("unknown dump file error code in sf_err()");
+               /* NOTREACHED */
+       }
+       abort();
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/savefile.h b/usr/src/contrib/tcpdump/tcpdump/savefile.h
new file mode 100644 (file)
index 0000000..a5082f9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Header: savefile.h,v 1.10 90/12/17 13:48:58 mccanne Exp $
+ *
+ * Header for offline storage info.
+ * Extraction/creation by Jeffrey Mogul, DECWRL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ */
+
+/*
+ * Each packet in the dump file is prepended with this generic header.
+ * This gets around the problem of different headers for different
+ * packet interfaces.
+ */
+struct packet_header {
+       struct timeval ts;      /* time stamp */
+       u_long len;             /* length this packet (off wire) */
+       u_long caplen;          /* length of portion present */
+};
+
+/* true if the contents of the savefile being read are byte-swapped */
+extern int sf_swapped;
+
+/* macros for when sf_swapped is true: */
+/*
+ * We use the "receiver-makes-right" approach to byte order,
+ * because time is at a premium when we are writing the file.
+ * In other words, the file_header and packet_header records
+ * are written in host byte order.
+ * Note that the packets are always written in network byte order.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define        SWAPLONG(y) \
+((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+#define        SWAPSHORT(y) \
+       ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
+
+
+extern FILE *sf_readfile;      /* dump file being read from */
+extern FILE *sf_writefile;     /* dump file being written to */
+
+int sf_read_init();
+int sf_read();
+int sf_next_packet();
+void sf_write_init();
+void sf_write();
+void sf_err();
+
+#define SFERR_TRUNC            1
+#define SFERR_BADVERSION       2
+#define SFERR_BADF             3
+#define SFERR_EOF              4 /* not really an error, just a status */
+
diff --git a/usr/src/contrib/tcpdump/tcpdump/tcpdump.1 b/usr/src/contrib/tcpdump/tcpdump/tcpdump.1
new file mode 100644 (file)
index 0000000..2406319
--- /dev/null
@@ -0,0 +1,1067 @@
+.\" @(#) $Header: tcpdump.1,v 1.40 92/01/29 16:56:02 mccanne Exp $ (LBL)
+.\"
+.\" Copyright (c) 1988, 1989, 1990, 1991, 1992
+.\" 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: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH TCPDUMP 1  "4 Jan 1992"
+.SH NAME
+tcpdump \- dump traffic on a network
+.SH SYNOPSIS
+.na
+.B tcpdump
+[
+.B \-deflnNOpqStvx
+] [
+.B \-c
+.I count
+] [
+.B \-F
+.I file
+]
+.br
+.ti +8
+[
+.B \-i
+.I interface
+] [
+.B \-r
+.I file
+]
+[
+.B \-s
+.I snaplen
+]
+.br
+.ti +8
+[
+.B \-w
+.I file
+]
+.I expression
+.br
+.ad
+.SH DESCRIPTION
+.LP
+\fITcpdump\fP prints out the headers of packets on a network interface
+that match the boolean \fIexpression\fP.
+.B Under SunOS:
+You must be root to invoke \fItcpdump\fP or it must be installed
+setuid to root.
+.B Under Ultrix:
+Any user can invoke \fItcpdump\fP once the super-user has enabled
+promiscuous-mode operation using
+.IR pfconfig (8).
+.B Under BSD:
+Access is controlled by the permissions on
+.I /dev/bpf0,
+etc.
+.SH OPTIONS
+.TP
+.B \-c
+Exit after receiving \fIcount\fP packets.
+.TP
+.B \-d
+Dump the compiled packet-matching code to standard output and stop.
+.TP
+.B \-e
+Print the link-level header on each dump line.
+.TP
+.B \-f
+Print `foreign' internet addresses numerically rather than symbolically
+(this option is intended to get around serious brain damage in
+Sun's yp server \(em usually it hangs forever translating non-local
+internet numbers).
+.TP
+.B \-F
+Use \fIfile\fP as input for the filter expression.
+An additional expression given on the command line is ignored.
+.TP
+.B \-i
+Listen on \fIinterface\fP.
+If unspecified, \fItcpdump\fP searches the system interface list for the
+lowest numbered, configured up interface (excluding loopback).
+Ties are broken by choosing the earliest match.
+.TP
+.B \-l
+Make stdout line buffered.  Useful if you want to see the data
+while capturing it.  E.g.,
+.br
+``tcpdump\ \ \-l\ \ |\ \ tee dat'' or
+``tcpdump\ \ \-l \ \ > dat\ \ &\ \ tail\ \ \-f\ \ dat''.
+.TP
+.B \-n
+Don't convert addresses (i.e., host addresses, port numbers, etc.) to names.
+.TP
+.B \-N
+Don't print domain name qualification of host names.  E.g.,
+if you give this flag then \fItcpdump\fP will print ``nic''
+instead of ``nic.ddn.mil''.
+.TP
+.B \-O
+Do not run the packet-matching code optimizer.  This is useful only
+if you suspect a bug in the optimizer.
+.TP
+.B \-p
+\fIDon't\fP put the interface
+into promiscuous mode.  Note that the interface might be in promiscuous
+for some other reason; hence, `-p' cannot be used as an abbreviation for
+`ether host {localhost} or broadcast'.
+.TP
+.B \-q
+Quick (quiet?) output.  Print less protocol information so output
+lines are shorter.
+.TP
+.B \-r
+Read packets from \fIfile\fR (which was created with the -w option).
+Standard input is used if \fIfile\fR is ``-''.
+.TP
+.B \-s
+Snarf \fIsnaplen\fP bytes of data from each packet rather than the
+default of 68 (with NIT, the minimum is actually 96).
+68 bytes is adequate for IP, ICMP, TCP
+and UDP but may truncate protocol information from name server and NFS
+packets (see below).  Packets truncated because of a limited snapshot
+are indicated in the output with ``[|\fIproto\fP]'', where \fIproto\fP
+is the name of the protocol level at which the truncation has occured.
+Note that taking larger snapshots both increases
+the amount of time it takes to process packets and, effectively,
+decreases the amount of packet buffering.  This may cause packets to be
+lost.  You should limit \fIsnaplen\fP to the smallest number that will
+capture the protocol information you're interested in.
+.TP
+.B \-S
+Print absolute, rather than relative, TCP sequence numbers.
+.TP
+.B \-t
+\fIDon't\fP print a timestamp on each dump line.
+.TP
+.B \-tt
+Print an unformatted timestamp on each dump line.
+.TP
+.B \-v
+(Slightly more) verbose output.  For example, the time to live
+and type of service information in an IP packet is printed.
+.TP
+.B \-w
+Write the raw packets to \fIfile\fR rather than parsing and printing
+them out.  They can later be printed with the \-r option.
+Standard output is used if \fIfile\fR is ``-''.
+.TP
+.B \-x
+Print each packet (minus its link level header) in hex.
+The smaller of the entire packet or
+.I snaplen
+bytes will be printed.
+.IP "\fI expression\fP"
+.RS
+selects which packets will be dumped.  If no \fIexpression\fP
+is given, all packets on the net will be dumped.  Otherwise,
+only packets for which \fIexpression\fP is `true' will be dumped.
+.LP
+The \fIexpression\fP consists of one or more
+.I primitives.
+Primitives usually consist of an
+.I id
+(name or number) preceded by one or more qualifiers.  There are three
+different kinds of qualifier:
+.IP \fItype\fP
+qualifiers say what kind of thing the id name or number refers to.
+Possible types are
+.BR host ,
+.B net
+and
+.BR port .
+E.g., `host foo', `net 128.3', `port 20'.  If there is no type
+qualifier,
+.B host
+is assumed.
+.IP \fIdir\fP
+qualifiers specify a particular tranfer direction to and/or from
+.I id.
+Possible directions are
+.BR src ,
+.BR dst ,
+.B "src or dst"
+and
+.BR "src and dst" .
+E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'.  If
+there is no dir qualifier,
+.B "src or dst"
+is assumed.
+.IP \fIproto\fP
+qualifiers restrict the match to a particular protocol.  Possible
+protos are:
+.BR ether ,
+.BR ip ,
+.BR arp ,
+.BR rarp ,
+.B tcp
+and
+.BR udp .
+E.g., `ether src foo', `arp net 128.3', `tcp port 21'.  If there is
+no proto qualifier, all protocols consistent with the type are
+assumed.  E.g., `src foo' means `(ip or arp or rarp) src foo'
+(except the latter is not legal syntax), `net bar' means `(ip or
+arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'.
+.LP
+In addition to the above, there are some special `primitive' keywords
+that don't follow the pattern:
+.BR gateway ,
+.BR broadcast ,
+.BR less ,
+.B greater
+and arithmetic expressions.  All of these are described below.
+.LP
+More complex filter expressions are built up by using the words
+.BR and ,
+.B or
+and
+.B not
+to combine primitives.  E.g., `host foo and not port ftp and not port ftp-data'.
+To save typing, identical qualifier lists can be omitted.  E.g.,
+`tcp dst port ftp or ftp-data or domain' is exactly the same as
+`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.
+.LP
+Allowable primitives are:
+.IP "\fBdst host \fIhost\fR"
+True if the IP destination field of the packet is \fIhost\fP,
+which may be either an address or a name.
+.IP "\fBsrc host \fIhost\fR"
+True if the IP source field of the packet is \fIhost\fP.
+.IP "\fBhost \fIhost\fP
+True if either the IP source or destination of the packet is \fIhost\fP.
+Any of the above host expressions can be prepended with the keywords,
+\fBip\fP, \fBarp\fP, or \fBrarp\fP as in:
+.in +.5i
+.nf
+\fBip host \fIhost\fR
+.fi
+.in -.5i
+which is equivalent to:
+.in +.5i
+.nf
+\fBether proto \fI\\ip\fB and host \fIhost\fR
+.fi
+.in -.5i
+If \fIhost\fR is a name with multiple IP addresses, each address will
+be checked for a match.
+.IP "\fBether dst \fIehost\fP
+True if the ethernet destination address is \fIehost\fP.  \fIEhost\fP
+may be either a name from /etc/ethers or a number (see
+.IR ethers (3N)
+for numeric format).
+.IP "\fBether src \fIehost\fP
+True if the ethernet source address is \fIehost\fP.
+.IP "\fBether host \fIehost\fP
+True if either the ethernet source or destination address is \fIehost\fP.
+.IP "\fBgateway\fP \fIhost\fP
+True if the packet used \fIhost\fP as a gateway.  I.e., the ethernet
+source or destination address was \fIhost\fP but neither the IP source
+nor the IP destination was \fIhost\fP.  \fIHost\fP must be a name and
+must be found in both /etc/hosts and /etc/ethers.  (An equivalent
+expression is
+.in +.5i
+.nf
+\fBether host \fIehost \fBand not host \fIhost\fR
+.fi
+.in -.5i
+which can be used with either names or numbers for \fIhost / ehost\fP.)
+.IP "\fBdst net \fInet\fR"
+True if the IP destination address of the packet has a network
+number of \fInet\fP, which may be either an address or a name.
+.IP "\fBsrc net \fInet\fR"
+True if the IP source address of the packet has a network
+number of \fInet\fP.
+.IP "\fBnet \fInet\fR"
+True if either the IP source or destination address of the packet has a network
+number of \fInet\fP.
+.IP "\fBdst port \fIport\fR"
+True if the packet is ip/tcp or ip/udp and has a
+destination port value of \fIport\fP.
+The \fIport\fP can be a number or a name used in /etc/services (see
+.IR tcp (4P)
+and
+.IR udp (4P)).
+If a name is used, both the port
+number and protocol are checked.  If a number or ambiguous name is used,
+only the port number is checked (e.g., \fBdst port 513\fR will print both
+tcp/login traffic and udp/who traffic, and \fBport domain\fR will print
+both tcp/domain and udp/domain traffic).
+.IP "\fBsrc port \fIport\fR"
+True if the packet has a source port value of \fIport\fP.
+.IP "\fBport \fIport\fR"
+True if either the source or destination port of the packet is \fIport\fP.
+Any of the above port expressions can be prepended with the keywords,
+\fBtcp\fP or \fBudp\fP, as in:
+.in +.5i
+.nf
+\fBtcp src port \fIport\fR
+.fi
+.in -.5i
+which matches only tcp packets.
+.IP "\fBless \fIlength\fR"
+True if the packet has a length less than or equal to \fIlength\fP.
+This is equivalent to:
+.in +.5i
+.nf
+\fBlen <= \fIlength\fP.
+.fi
+.in -.5i
+.IP "\fBgreater \fIlength\fR"
+True if the packet has a length greater than or equal to \fIlength\fP.
+This is equivalent to:
+.in +.5i
+.nf
+\fBlen >= \fIlength\fP.
+.fi
+.in -.5i
+.IP "\fBip proto \fIprotocol\fR"
+True if the packet is an ip packet (see
+.IR ip (4P))
+of protocol type \fIprotocol\fP.
+\fIProtocol\fP can be a number or one of the names
+\fIicmp\fP, \fIudp\fP, \fInd\fP, or \fItcp\fP.
+Note that the identifiers \fItcp\fP, \fIudp\fP, and \fIicmp\fP are also
+keywords and must be escaped via backslash (\\), which is \\\\ in the C-shell.
+.IP "\fBether broadcast\fR"
+True if the packet is an ethernet broadcast packet.  The \fIether\fP
+keyword is optional.
+.IP "\fBip broadcast\fR"
+True if the packet is an IP broadcast packet.  It checks for both
+the all-zeroes and all-ones broadcast conventions, and looks up
+the local subnet mask.
+.IP "\fBether multicast\fR"
+True if the packet is an ethernet multicast packet.  The \fIether\fP
+keyword is optional.
+This is shorthand for `\fBether[0] & 1 != 0\fP'.
+.IP "\fBip multicast\fR"
+True if the packet is an IP multicast packet.
+.IP  "\fBether proto \fIprotocol\fR"
+True if the packet is of ether type \fIprotocol\fR.
+\fIProtocol\fP can be a number or a name like
+\fIip\fP, \fIarp\fP, or \fIrarp\fP.
+Note these identifiers are also keywords
+and must be escaped via backslash (\\).
+.IP "\fBip\fR, \fBarp\fR, \fBrarp\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBether proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above protocols.
+.IP  "\fBtcp\fR, \fBudp\fR, \fBicmp\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBip proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above protocols.
+.IP  "\fIexpr relop expr\fR"
+True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=,
+and \fIexpr\fR is an arithmetic expression composed of integer constants
+(expressed in standard C syntax), the normal binary operators
+[+, -, *, /, &, |], a length operator, and special packet data accessors.
+To access
+data inside the packet, use the following syntax:
+.in +.5i
+.nf
+\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR
+.fi
+.in -.5i
+\fIProto\fR is one of \fBether, ip, arp, rarp, tcp, udp, \fRor \fBicmp\fR, and
+indicates the protocol layer for the index operation.
+The byte offset, relative to the indicated protocol layer, is
+given by \fIexpr\fR.
+\fISize\fR is optional and indicates the number of bytes in the
+field of interest; it can be either one, two, or four, and defaults to one.
+The length operator, indicated by the keyword \fBlen\fP, gives the
+length of the packet.
+
+For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic.
+The expression `\fBip[0] & 0xf != 5\fP'
+catches all IP packets with options. The expression
+`\fBip[2:2] & 0x1fff = 0\fP'
+catches only unfragmented datagrams and frag zero of fragmented datagrams.
+This check is implicitly applied to the \fBtcp\fP and \fBudp\fP
+index opertations.
+For instance, \fBtcp[0]\fP always means the first
+byte of the TCP \fIheader\fP, and never means the first byte of an
+intervening fragment.
+.LP
+Primitives may be combined using:
+.IP
+A parenthesized group of primitives and operators
+(parentheses are special to the Shell and must be escaped).
+.IP
+Negation (`\fB!\fP' or `\fBnot\fP').
+.IP
+Concatenation (`\fBand\fP').
+.IP
+Alternation (`\fBor\fP').
+.LP
+Negation has highest precedence.
+Alternation and concatenation have equal precedence and associate
+left to right.  Note that explicit \fBand\fR tokens, not juxtaposition,
+are now required for concatenation.
+.LP
+If an identifier is given without a keyword, the most recent keyword
+is assumed.
+For example,
+.in +.5i
+.nf
+\fBnot host vs and ace\fR
+.fi
+.in -.5i
+is short for
+.in +.5i
+.nf
+\fBnot host vs and host ace\fR
+.fi
+.in -.5i
+which should not be confused with
+.in +.5i
+.nf
+\fBnot ( host vs or ace )\fR
+.fi
+.in -.5i
+.LP
+Expression arguments can be passed to tcpdump as either a single argument
+or as multiple arguments, whichever is more convenient.
+Generally, if the expression contains Shell metacharacters, it is
+easier to pass it as a single, quoted argument.
+Multiple arguments are concatenated with spaces before being parsed.
+.SH EXAMPLES
+.LP
+To print all packets arriving at or departing from \fIsundown\fP:
+.RS
+.nf
+\fBtcpdump host sundown\fP
+.fi
+.RE
+.LP
+To print traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR:
+.RS
+.nf
+\fBtcpdump host helios and \\( hot or ace \\)\fP
+.fi
+.RE
+.LP
+To print all IP packets between \fIace\fR and any host except \fIhelios\fR:
+.RS
+.nf
+\fBtcpdump ip host ace and not helios\fP
+.fi
+.RE
+.LP
+To print all traffic between local hosts and hosts at Berkeley:
+.RS
+.nf
+.B
+tcpdump net ucb-ether
+.fi
+.RE
+.LP
+To print all ftp traffic through internet gateway \fIsnup\fP:
+(note that the expression is quoted to prevent the shell from
+(mis-)interpreting the parentheses):
+.RS
+.nf
+.B
+tcpdump 'gateway snup and (port ftp or ftp-data)'
+.fi
+.RE
+.LP
+To print traffic neither sourced from nor destined for local hosts
+(if you gateway to one other net, this stuff should never make it
+onto your local net).
+.RS
+.nf
+.B
+tcpdump ip and not net \fIlocalnet\fP
+.fi
+.RE
+.LP
+To print the start and end packets (the SYN and FIN packets) of each
+TCP conversation that involves a non-local host.
+.RS
+.nf
+.B
+tcpdump 'tcp[13] & 3 != 0 and not src and dst net \fIlocalnet\fP'
+.fi
+.RE
+.LP
+To print IP packets longer than 576 bytes sent through gateway \fIsnup\fP:
+.RS
+.nf
+.B
+tcpdump 'gateway snup and ip[2:2] > 576'
+.fi
+.RE
+.LP
+To print IP broadcast or multicast packets that were
+.I not
+sent via ethernet broadcast or multicast:
+.RS
+.nf
+.B
+tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
+.fi
+.RE
+.LP
+To print all ICMP packets that are not echo requests/replies (i.e., not
+ping packets):
+.RS
+.nf
+.B
+tcpdump 'icmp[0] != 8 and icmp[0] != 0"
+.fi
+.RE
+.SH OUTPUT FORMAT
+.LP
+The output of \fItcpdump\fP is protocol dependent.  The following
+gives a brief description and examples of most of the formats.
+.de HD
+.sp 1.5
+.B
+..
+.HD
+Link Level Headers
+.LP
+If the '-e' option is given, the link level header is printed out.
+On ethernets, the source and destination addresses, protocol,
+and packet length are printed.
+.LP
+\fI(N.B.: The following description assumes familiarity with
+the SLIP compression algorithm described in RFC-1144.)\fP
+.LP
+On SLIP links, a direction indicator (``I'' for inbound, ``O'' for outbound),
+packet type, and compression information are printed out.
+The packet type is printed first.
+The three types are \fIip\fP, \fIutcp\fP, and \fIctcp\fP.
+No further link information is printed for \fIip\fR packets.
+For TCP packets, the connection identifier is printed following the type.
+If the packet is compressed, its encoded header is printed out.
+The special cases are printed out as
+\fB*S+\fIn\fR and \fB*SA+\fIn\fR, where \fIn\fR is the amount by which
+the sequence number (or sequence number and ack) has changed.
+If it is not a special case,
+zero or more changes are printed.
+A change is indicated by U (urgent pointer), W (window), A (ack),
+S (sequence number), and I (packet ID), followed by a delta (+n or -n),
+or a new value (=n).
+Finally, the amount of data in the packet and compressed header length
+are printed.
+.LP
+For example, the following line shows an outbound compressed TCP packet,
+with an implicit connection identifier; the ack has changed by 6,
+the sequence number by 49, and the packet ID by 6; there are 3 bytes of
+data and 6 bytes of compressed header:
+.RS
+.nf
+\fBO ctcp * A+6 S+49 I+6 3 (6)\fP
+.fi
+.RE
+.HD
+ARP/RARP Packets
+.LP
+Arp/rarp output shows the type of request and its arguments.  The
+format is intended to be self explanatory.
+Here is a short sample taken from the start of an `rlogin' from
+host \fIrtsg\fP to host \fIcsam\fP:
+.RS
+.nf
+.sp .5
+\f(CWarp who-has csam tell rtsg
+arp reply csam is-at CSAM\fP
+.sp .5
+.fi
+.RE
+The first line says that rtsg sent an arp packet asking
+for the ethernet address of internet host csam.  Csam
+replies with its ethernet address (in this example, ethernet addresses
+are in caps and internet addresses in lower case).
+.LP
+This would look less redundant if we had done \fBtcpdump \-n\fP:
+.RS
+.nf
+.sp .5
+\f(CWarp who-has 128.3.254.6 tell 128.3.254.68
+arp reply 128.3.254.6 is-at 02:07:01:00:01:c4\fP
+.fi
+.RE
+.LP
+If we had done \fBtcpdump \-e\fP, the fact that the first packet is
+broadcast and the second is point-to-point would be visible:
+.RS
+.nf
+.sp .5
+\f(CWRTSG Broadcast 0806  64: arp who-has csam tell rtsg
+CSAM RTSG 0806  64: arp reply csam is-at CSAM\fP
+.sp .5
+.fi
+.RE
+For the first packet this says the ethernet source address is RTSG, the
+destination is the broadcast address, the type field
+contained hex 0806 (type ETHER_ARP) and the total length was 64 bytes.
+.HD
+TCP Packets
+.LP
+\fI(N.B.:The following description assumes familiarity with
+the TCP protocol described in RFC-793.  If you are not familiar
+with the protocol, neither this description nor tcpdump will
+be of much use to you.)\fP
+.LP
+The general format of a tcp protocol line is:
+.RS
+.nf
+.sp .5
+\fIsrc > dst: flags data-seqno ack window urgent options\fP
+.sp .5
+.fi
+.RE
+\fISrc\fP and \fIdst\fP are the source and destination IP
+addresses and ports.  \fIFlags\fP are some combination of S (SYN),
+F (FIN), P (PUSH) or R (RST) or a single `.' (no flags).
+\fIData-seqno\fP describes the portion of sequence space covered
+by the data in this packet (see example below).
+\fIAck\fP is sequence number of the next data expected the other
+direction on this connection.
+\fIWindow\fP is the number of bytes of receive buffer space available
+the other direction on this connection.
+\fIUrg\fP indicates there is `urgent' data in the packet.
+\fIOptions\fP are tcp options enclosed in angle brackets (e.g., <mss 1024>).
+.LP
+\fISrc, dst\fP and \fIflags\fP are always present.  The other fields
+depend on the contents of the packet's tcp protocol header and
+are output only if appropriate.
+.LP
+Here is the opening portion of an rlogin from host \fIrtsg\fP to
+host \fIcsam\fP.
+.RS
+.nf
+.sp .5
+\s-2\f(CWrtsg.1023 > csam.login: S 768512:768512(0) win 4096 <mss 1024>
+csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 <mss 1024>
+rtsg.1023 > csam.login: . ack 1 win 4096
+rtsg.1023 > csam.login: P 1:2(1) ack 1 win 4096
+csam.login > rtsg.1023: . ack 2 win 4096
+rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096
+csam.login > rtsg.1023: P 1:2(1) ack 21 win 4077
+csam.login > rtsg.1023: P 2:3(1) ack 21 win 4077 urg 1
+csam.login > rtsg.1023: P 3:4(1) ack 21 win 4077 urg 1\fP\s+2
+.sp .5
+.fi
+.RE
+The first line says that tcp port 1023 on rtsg sent a packet
+to port \fIlogin\fP
+on csam.  The \fBS\fP indicates that the \fISYN\fP flag was set.
+The packet sequence number was 768512 and it contained no data.
+(The notation is `first:last(nbytes)' which means `sequence
+numbers \fIfirst\fP
+up to but not including \fIlast\fP which is \fInbytes\fP bytes of user data'.)
+There was no piggy-backed ack, the available receive window was 4096
+bytes and there was a max-segment-size option requesting an mss of
+1024 bytes.
+.LP
+Csam replies with a similar packet except it includes a piggy-backed
+ack for rtsg's SYN.  Rtsg then acks csam's SYN.  The `.' means no
+flags were set.
+The packet contained no data so there is no data sequence number.
+Note that the ack sequence
+number is a small integer (1).  The first time \fBtcpdump\fP sees a
+tcp `conversation', it prints the sequence number from the packet.
+On subsequent packets of the conversation, the difference between
+the current packet's sequence number and this initial sequence number
+is printed.  This means that sequence numbers after the
+first can be interpreted
+as relative byte positions in the conversation's data stream (with the
+first data byte each direction being `1').  `-S' will override this
+feature, causing the original sequence numbers to be output.
+.LP
+On the 6th line, rtsg sends csam 19 bytes of data (bytes 2 through 20
+in the rtsg \(-> csam side of the conversation).
+The PUSH flag is set in the packet.
+On the 7th line, csam says it's received data sent by rtsg up to
+but not including byte 21.  Most of this data is apparently sitting in the
+socket buffer since csam's receive window has gotten 19 bytes smaller.
+Csam also sends one byte of data to rtsg in this packet.
+On the 8th and 9th lines,
+csam sends two bytes of urgent, pushed data to rtsg.
+.HD
+.B
+UDP Packets
+.LP
+UDP format is illustrated by this rwho packet:
+.RS
+.nf
+.sp .5
+\f(CWactinide.who > broadcast.who: udp 84\fP
+.sp .5
+.fi
+.RE
+This says that port \fIwho\fP on host \fIactinide\fP sent a udp
+datagram to port \fIwho\fP on host \fIbroadcast\fP, the Internet
+broadcast address.  The packet contained 84 bytes of user data.
+.LP
+Some UDP services are recognized (from the source or destination
+port number) and the higher level protocol information printed.
+In particular, Domain Name service requests (RFC-1034/1035) and Sun
+RPC calls (RFC-1050) to NFS.
+.HD
+UDP Name Server Requests
+.LP
+\fI(N.B.:The following description assumes familiarity with
+the Domain Service protocol described in RFC-1035.  If you are not familiar
+with the protocol, the following description will appear to be written
+in greek.)\fP
+.LP
+Name server requests are formatted as
+.RS
+.nf
+.sp .5
+\fIsrc > dst: id op? flags qtype qclass name (len)\fP
+.sp .5
+\f(CWh2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)\fP
+.sp .5
+.fi
+.RE
+Host \fIh2opolo\fP asked the domain server on \fIhelios\fP for an
+address record (qtype=A) associated with the name \fIucbvax.berkeley.edu.\fP
+The query id was `3'.  The `+' indicates the \fIrecursion desired\fP flag
+was set.  The query length was 37 bytes, not including the UDP and
+IP protocol headers.  The query operation was the normal one, \fIQuery\fP,
+so the op field was omitted.  If the op had been anything else, it would
+have been printed between the `3' and the `+'.
+Similarly, the qclass was the normal one,
+\fIC_IN\fP, and omitted.  Any other qclass would have been printed
+immediately after the `A'.
+.LP
+A few anomalies are checked and may result in extra fields enclosed in
+square brackets:  If a query contains an answer, name server or
+authority section,
+.IR ancount ,
+.IR nscount ,
+or
+.I arcount
+are printed as `[\fIn\fPa]', `[\fIn\fPn]' or  `[\fIn\fPau]' where \fIn\fP
+is the appropriate count.
+If any of the response bits are set (AA, RA or rcode) or any of the
+`must be zero' bits are set in bytes two and three, `[b2&3=\fIx\fP]'
+is printed, where \fIx\fP is the hex value of header bytes two and three.
+.HD
+UDP Name Server Responses
+.LP
+Name server responses are formatted as
+.RS
+.nf
+.sp .5
+\fIsrc > dst:  id op rcode flags a/n/au type class data (len)\fP
+.sp .5
+\f(CWhelios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273)
+helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)\fP
+.sp .5
+.fi
+.RE
+In the first example, \fIhelios\fP responds to query id 3 from \fIh2opolo\fP
+with 3 answer records, 3 name server records and 7 authority records.
+The first answer record is type A (address) and its data is internet
+address 128.32.137.3.  The total size of the response was 273 bytes,
+excluding UDP and IP headers.  The op (Query) and response code
+(NoError) were omitted, as was the class (C_IN) of the A record.
+.LP
+In the second example, \fIhelios\fP responds to query 2 with a
+response code of non-existent domain (NXDomain) with no answers,
+one name server and no authority records.  The `*' indicates that
+the \fIauthoritative answer\fP bit was set.  Since there were no
+answers, no type, class or data were printed.
+.LP
+Other flag characters that might appear are `\-' (recursion available,
+RA, \fInot\fP set) and `|' (truncated message, TC, set).  If the
+`question' section doesn't contain exactly one entry, `[\fIn\fPq]'
+is printed.
+.LP
+Note that name server requests and responses tend to be large and the
+default \fIsnaplen\fP of 96 bytes may not capture enough of the packet
+to print.  Use the \fB\-s\fP flag to increase the snaplen if you
+need to seriously investigate name server traffic.  `\fB\-s 128\fP'
+has worked well for me.
+
+.HD
+NFS Requests
+.LP
+Sun NFS (Network File System) requests and replies are printed as:
+.RS
+.nf
+.sp .5
+\fIsrc.xid > dst.nfs: len op args\fP
+\fIsrc.nfs > dst.xid: reply stat len\fP
+.sp .5
+\f(CWvs.e2766 > helios.nfs: 136 readdir fh 6.5197 8192 bytes @ 0
+helios.nfs > vs.e2766: reply ok 384
+vs.e2767 > helios.nfs: 136 lookup fh 6.5197 `RCS'\fP
+.sp .5
+.fi
+.RE
+In the first line, host \fIvs\fP sends a transaction with id \fIe2766\fP
+to \fIhelios\fP (note that the number following the src host is a
+transaction id, \fInot\fP the source port).  The request was 136 bytes,
+excluding the UDP and IP headers.  The operation was a \fIreaddir\fP
+(read directory) on file handle (\fIfh\fP) 6.5197.  8192 bytes are
+read, starting at offset 0.  \fIHelios\fP replies `ok' with 384
+bytes of data.  (The design of Sun's RPC protocol makes it difficult to
+interpret replies.  I don't bother.)
+.LP
+In the third line, \fIvs\fP asks \fIhelios\fP to lookup the name
+`\fIRCS\fP' in directory file 6.5197.  Note that the data printed
+depends on the operation type.  The format is intended to be self
+explanatory (at least, to me) if read in conjunction with
+an NFS protocol spec.
+.LP
+Note that NFS requests are very large and the above won't be printed
+unless \fIsnaplen\fP is increased.  I use `\fB\-s 192\fP' to watch
+NFS traffic.
+
+.HD
+KIP Appletalk (DDP in UDP)
+.LP
+Appletalk DDP packets encapsulated in UDP datagrams are de-encapsulated
+and dumped as DDP packets (i.e., all the UDP header information is
+discarded).  The file
+.I /etc/atalk.names
+is used to translate appletalk net and node numbers to names.
+Lines in this file have the form
+.RS
+.nf
+.sp .5
+\fInumber      name\fP
+
+\f(CW1.254             ether
+16.1           icsd-net
+1.254.110      ace\fP
+.sp .5
+.fi
+.RE
+The first two lines give the names of appletalk networks.  The third
+line gives the name of a particular host (a host is distinguished
+from a net by the 3rd octet in the number \-
+a net number \fImust\fP have two octets and a host number \fImust\fP
+have three octets.)  The number and name should be separated by
+whitespace (blanks or tabs).
+The
+.I /etc/atalk.names
+file may contain blank lines or comment lines (lines starting with
+a `#').
+.LP
+Appletalk addresses are printed in the form
+.RS
+.nf
+.sp .5
+\fInet.host.port\fP
+
+\f(CW144.1.209.2 > icsd-net.112.220
+office.2 > icsd-net.112.220
+jssmag.149.235 > icsd-net.2\fP
+.sp .5
+.fi
+.RE
+(If the
+.I /etc/atalk.names
+doesn't exist or doesn't contain an entry for some appletalk
+host/net number, addresses are printed in numeric form.)
+In the first example, NBP (DDP port 2) on net 144.1 node 209
+is sending to whatever is listening on port 220 of net icsd node 112.
+The second line is the same except the full name of the source node
+is known (`office').  The third line is a send from port 235 on
+net jssmag node 149 to broadcast on the icsd-net NBP port (note that
+the broadcast address (255) is indicated by a net name with no host
+number \- for this reason it's a good idea to keep node names and
+net names distinct in /etc/atalk.names).
+.LP
+NBP (name binding protocol) and ATP (Appletalk transaction protocol)
+packets have their contents interpreted.  Other protocols just dump
+the protocol name (or number if no name is registered for the
+protocol) and packet size.
+
+\fBNBP packets\fP are formatted like the following examples:
+.RS
+.nf
+.sp .5
+\s-2\f(CWicsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*"
+jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250
+techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186\fP\s+2
+.sp .5
+.fi
+.RE
+The first line is a name lookup request for laserwriters sent by net icsd host
+112 and broadcast on net jssmag.  The nbp id for the lookup is 190.
+The second line shows a reply for this request (note that it has the
+same id) from host jssmag.209 saying that it has a laserwriter
+resource named "RM1140" registered on port 250.  The third line is
+another reply to the same request saying host techpit has laserwriter
+"techpit" registered on port 186.
+
+\fBATP packet\fP formatting is demonstrated by the following example:
+.RS
+.nf
+.sp .5
+\s-2\f(CWjssmag.209.165 > helios.132: atp-req  12266<0-7> 0xae030001
+helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000
+jssmag.209.165 > helios.132: atp-req  12266<3,5> 0xae030001
+helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000
+helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000
+jssmag.209.165 > helios.132: atp-rel  12266<0-7> 0xae030001
+jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002\fP\s+2
+.sp .5
+.fi
+.RE
+Jssmag.209 initiates transaction id 12266 with host helios by requesting
+up to 8 packets (the `<0-7>').  The hex number at the end of the line
+is the value of the `userdata' field in the request.
+.LP
+Helios responds with 8 512-byte packets.  The `:digit' following the
+transaction id gives the packet sequence number in the transaction
+and the number in parens is the amount of data in the packet,
+excluding the atp header.  The `*' on packet 7 indicates that the
+EOM bit was set.
+.LP
+Jssmag.209 then requests that packets 3 & 5 be retransmitted.  Helios
+resends them then jssmag.209 releases the transaction.  Finally,
+jssmag.209 initiates the next request.  The `*' on the request
+indicates that XO (`exactly once') was \fInot\fP set.
+
+.HD
+IP Fragmentation
+.LP
+Fragmented Internet datagrams are printed as
+.RS
+.nf
+.sp .5
+\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB+)\fR
+\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB)\fR
+.sp .5
+.fi
+.RE
+(The first form indicates there are more fragments.  The second
+indicates this is the last fragment.)
+.LP
+\fIId\fP is the fragment id.  \fISize\fP is the fragment
+size (in bytes) excluding the IP header.  \fIOffset\fP is this
+fragment's offset (in bytes) in the original datagram.
+.LP
+The fragment information is output for each fragment.  The first
+fragment contains the higher level protocol header and the frag
+info is printed after the protocol info.  Fragments
+after the first contain no higher level protocol header and the
+frag info is printed after the source and destination addresses.
+For example, here is part of an ftp from arizona.edu to lbl-rtsg.arpa
+over a CSNET connection that doesn't appear to handle 576 byte datagrams:
+.RS
+.nf
+.sp .5
+\s-2\f(CWarizona.ftp-data > rtsg.1170: . 1024:1332(308) ack 1 win 4096 (frag 595a:328@0+)
+arizona > rtsg: (frag 595a:204@328)
+rtsg.1170 > arizona.ftp-data: . ack 1536 win 2560\fP\s+2
+.sp .5
+.fi
+.RE
+There are a couple of things to note here:  First, addresses in the
+2nd line don't include port numbers.  This is because the TCP
+protocol information is all in the first fragment and we have no idea
+what the port or sequence numbers are when we print the later fragments.
+Second, the tcp sequence information in the first line is printed as if there
+were 308 bytes of user data when, in fact, there are 512 bytes (308 in
+the first frag and 204 in the second).  If you are looking for holes
+in the sequence space or trying to match up acks
+with packets, this can fool you.
+.LP
+A packet with the IP \fIdon't fragment\fP flag is marked with a
+trailing \fB(DF)\fP.
+.HD
+Timestamps
+.LP
+By default, all output lines are preceded by a timestamp.  The timestamp
+is the current clock time in the form
+.RS
+.nf
+\fIhh:mm:ss.frac\fP
+.fi
+.RE
+and is as accurate as the kernel's clock (e.g., \(+-10ms on a Sun-3).
+The timestamp reflects the time the kernel first saw the packet.  No attempt
+is made to account for the time lag between when the
+ethernet interface removed the packet from the wire and when the kernel
+serviced the `new packet' interrupt (of course,
+with Sun's lousy clock resolution this time lag is negligible.)
+.SH "SEE ALSO"
+traffic(1C), nit(4P), bpf(4)
+.SH AUTHORS
+Van Jacobson (van@helios.ee.lbl.gov),
+Craig Leres (leres@helios.ee.lbl.gov) and
+Steven McCanne (mccanne@helios.ee.lbl.gov), all of
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
+.SH BUGS
+The clock resolution on most Suns is pathetic (20ms).
+If you want to use the timestamp to generate some of the important
+performance distributions (like packet interarrival time) it's best
+to watch something that generates packets slowly (like an Arpanet
+gateway or a MicroVax running VMS).
+.LP
+NIT doesn't let you watch your own outbound traffic, BPF will.
+We recommend that you use the latter.
+.LP
+\fItcpdump\fP for Ultrix requires Ultrix version 4.0 or later; the kernel
+has to have been built with the \fIpacketfilter\fP pseudo-device driver
+(see
+.IR packetfilter (4)).
+As of this writing, Ultrix does not let you
+watch either your own outbound or inbound traffic.
+.LP
+Under SunOS 4.1, the packet capture code (or Streams NIT) is not what
+you'd call efficient.  Don't plan on doing much with your Sun while
+you're monitoring a busy network.
+.LP
+On Sun systems prior to release 3.2, NIT is very buggy.
+If run on an old system, tcpdump may crash the machine.
+.LP
+Some attempt should be made to reassemble IP fragments or, at least
+to compute the right length for the higher level protocol.
+.LP
+Name server inverse queries are not dumped correctly: The (empty)
+question section is printed rather than real query in the answer
+section.  Some believe that inverse queries are themselves a bug and
+prefer to fix the program generating them rather than tcpdump.
+.LP
+Apple Ethertalk DDP packets could be dumped as easily as KIP DDP
+packets but aren't.
+Even if we were inclined to do anything to promote the use of
+Ethertalk (we aren't), LBL doesn't allow Ethertalk on any of its
+networks so we'd would have no way of testing this code.
+.LP
+A packet trace that crosses a daylight savings time change will give
+skewed time stamps (the time change is ignored).
diff --git a/usr/src/contrib/tcpdump/tcpdump/tcpdump.c b/usr/src/contrib/tcpdump/tcpdump/tcpdump.c
new file mode 100644 (file)
index 0000000..9a0ccc4
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1987-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+char copyright[] =
+    "@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
+static  char rcsid[] =
+    "@(#)$Header: tcpdump.c,v 1.68 92/06/02 17:57:41 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * tcpdump - monitor tcp/ip traffic on an ethernet.
+ *
+ * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory.
+ * Mercilessly hacked and occasionally improved since then via the
+ * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <netinet/in.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "savefile.h"
+#include "addrtoname.h"
+
+int fflag;                     /* don't translate "foreign" IP address */
+int nflag;                     /* leave addresses as numbers */
+int Nflag;                     /* remove domains from printed host names */
+int pflag;                     /* don't go promiscuous */
+int qflag;                     /* quick (shorter) output */
+int tflag = 1;                 /* print packet arrival time */
+int eflag;                     /* print ethernet header */
+int vflag;                     /* verbose */
+int xflag;                     /* print packet in hex */
+int Oflag = 1;                 /* run filter code optimizer */
+int Sflag;                     /* print raw TCP sequence numbers */
+
+int dflag;                     /* print filter code */
+
+char *program_name;
+
+long thiszone;                 /* gmt to local correction */
+
+static void cleanup();
+
+/* Length of saved portion of packet. */
+int snaplen = DEFAULT_SNAPLEN;
+
+static int if_fd = -1;
+
+struct printer {
+       void (*f)();
+       int type;
+};
+
+static struct printer printers[] = {
+       { ether_if_print, DLT_EN10MB },
+       { sl_if_print, DLT_SLIP },
+       { ppp_if_print, DLT_PPP },
+       { fddi_if_print, DLT_FDDI },
+       { null_if_print, DLT_NULL },
+       { 0, 0 },
+};
+
+void
+(*lookup_printer(type))()
+       int type;
+{
+       struct printer *p;
+
+       for (p = printers; p->f; ++p)
+               if (type == p->type)
+                       return p->f;
+
+       error("unknown data link type 0x%x", type);
+       /* NOTREACHED */
+}
+
+void
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       struct bpf_program *parse();
+       void bpf_dump();
+
+       int cnt = -1, i;
+       struct timeb zt;
+       struct bpf_program *fcode;
+       int op;
+       void (*printit)();
+       char *infile = 0;
+       char *cmdbuf;
+       int linktype;
+       int err;
+       u_long localnet;
+       u_long netmask;
+
+       char *RFileName = 0;    /* -r argument */
+       char *WFileName = 0;    /* -w argument */
+
+       char *device = 0;
+
+       int precision = clock_sigfigs();
+
+       extern char *optarg;
+       extern int optind, opterr;
+
+       program_name = argv[0];
+
+       opterr = 0;
+       while ((op = getopt(argc, argv, "c:defF:i:lnNOpqr:s:Stvw:xY")) != EOF)
+               switch (op) {
+               case 'c':
+                       cnt = atoi(optarg);
+                       break;
+
+               case 'd':
+                       ++dflag;
+                       break;
+
+               case 'e':
+                       ++eflag;
+                       break;
+
+               case 'f':
+                       ++fflag;
+                       break;
+
+               case 'F':
+                       infile = optarg;
+                       break;
+
+               case 'i':
+                       device = optarg;
+                       break;
+
+               case 'l':
+                       setlinebuf(stdout);
+                       break;
+
+               case 'n':
+                       ++nflag;
+                       break;
+
+               case 'N':
+                       ++Nflag;
+                       break;
+
+               case 'O':
+                       Oflag = 0;
+                       break;
+
+               case 'p':
+                       ++pflag;
+                       break;
+
+               case 'q':
+                       ++qflag;
+                       break;
+
+               case 'r':
+                       RFileName = optarg;
+                       break;
+
+               case 's':
+                       snaplen = atoi(optarg);
+                       break;
+
+               case 'S':
+                       ++Sflag;
+                       break;
+
+               case 't':
+                       --tflag;
+                       break;
+
+               case 'v':
+                       ++vflag;
+                       break;
+
+               case 'w':
+                       WFileName = optarg;
+                       break;
+#ifdef YYDEBUG
+               case 'Y':
+                       {
+                       extern int yydebug;
+                       yydebug = 1;
+                       }
+                       break;
+#endif
+               case 'x':
+                       ++xflag;
+                       break;
+
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+
+       if (tflag > 0) {
+               struct timeval now;
+               struct timezone tz;
+
+               if (gettimeofday(&now, &tz) < 0) {
+                       perror("tcpdump: gettimeofday");
+                       exit(1);
+               }
+               thiszone = tz.tz_minuteswest * -60;
+               if (localtime((time_t *)&now.tv_sec)->tm_isdst)
+                       thiszone += 3600;
+       }
+
+       if (RFileName) {
+               /*
+                * We don't need network access, so set it back to the user id.
+                * Also, this prevents the user from reading anyone's
+                * trace file.
+                */
+               setuid(getuid());
+
+               err = sf_read_init(RFileName, &linktype, &thiszone, &snaplen,
+                       &precision);
+               if (err)
+                       sf_err(err);
+               localnet = 0;
+               netmask = 0;
+               if (fflag != 0)
+                       error("-f and -r options are incompatible");
+       } else {
+               if (device == 0) {
+                       device = lookup_device();
+                       if (device == 0)
+                               error("can't find any interfaces");
+               }
+               if_fd = initdevice(device, pflag, &linktype);
+               lookup_net(device, &localnet, &netmask);
+               /*
+                * Let user own process after socket has been opened.
+                */
+               setuid(getuid());
+       }
+
+       if (infile) 
+               cmdbuf = read_infile(infile);
+       else
+               cmdbuf = copy_argv(&argv[optind]);
+
+       fcode = parse(cmdbuf, Oflag, linktype, netmask);
+       if (dflag) {
+               bpf_dump(fcode, dflag);
+               exit(0);
+       }
+       init_addrtoname(fflag, localnet, netmask);
+
+       (void)signal(SIGTERM, cleanup);
+       (void)signal(SIGINT, cleanup);
+       (void)signal(SIGHUP, cleanup);
+
+       printit = lookup_printer(linktype);
+
+       if (WFileName) {
+               sf_write_init(WFileName, linktype, thiszone, snaplen, 
+                             precision);
+               printit = sf_write;
+       }
+       if (RFileName) {
+               err = sf_read(fcode, cnt, snaplen, printit);
+               if (err)
+                       sf_err(err);
+       } else {
+               fprintf(stderr, "%s: listening on %s\n", program_name, device);
+               fflush(stderr);
+               readloop(cnt, if_fd, fcode, printit);
+       }
+       exit(0);
+}
+
+/* make a clean exit on interrupts */
+static void
+cleanup()
+{
+       if (if_fd >= 0) {
+               putc('\n', stderr);
+               wrapup(if_fd);
+       }
+       exit(0);
+}
+
+void
+default_print(sp, length)
+       register u_short *sp;
+       register int length;
+{
+       register u_int i;
+       register int nshorts;
+
+       nshorts = (unsigned) length / sizeof(u_short);
+       i = 0;
+       while (--nshorts >= 0) {
+               if ((i++ % 8) == 0)
+                       (void)printf("\n\t\t\t");
+               (void)printf(" %04x", ntohs(*sp++));
+       }
+       if (length & 1) {
+               if ((i % 8) == 0)
+                       (void)printf("\n\t\t\t");
+               (void)printf(" %02x", *(u_char *)sp);
+       }
+}
+
+void
+usage()
+{
+       extern char version[];
+
+       (void)fprintf(stderr, "Version %s\n", version);
+       (void)fprintf(stderr,
+"Usage: tcpdump [-deflnOpqtvx] [-c count] [-i interface]\n");
+       (void)fprintf(stderr,
+"\t\t[-r filename] [-w filename] [expr]\n");
+       exit(-1);
+}
diff --git a/usr/src/contrib/tcpdump/tcpdump/tcpgram.y b/usr/src/contrib/tcpdump/tcpdump/tcpgram.y
new file mode 100644 (file)
index 0000000..da235d0
--- /dev/null
@@ -0,0 +1,232 @@
+%{
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Grammar for tcpdump.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: tcpgram.y,v 1.29 92/03/17 13:45:08 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "interface.h"
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "gencode.h"
+
+#define QSET(q, p, d, a) (q).proto = (p),\
+                        (q).dir = (d),\
+                        (q).addr = (a)
+
+int n_errors = 0;
+
+static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
+
+static void
+yyerror()
+{
+       ++n_errors;
+}
+
+%}
+
+%union {
+       int i;
+       u_long h;
+       u_char *e;
+       char *s;
+       struct stmt *stmt;
+       struct arth *a;
+       struct {
+               struct qual q;
+               struct block *b;
+       } blk;
+       struct block *rblk;
+}
+
+%type  <blk>   expr id nid pid term rterm qid
+%type  <blk>   head
+%type  <i>     pqual dqual aqual ndaqual
+%type  <a>     arth narth
+%type  <i>     byteop pname pnum relop irelop
+%type  <blk>   and or paren not null prog
+%type  <rblk>  other
+
+%token  DST SRC HOST GATEWAY
+%token  NET PORT LESS GREATER PROTO BYTE
+%token  ARP RARP IP TCP UDP ICMP
+%token  TK_BROADCAST TK_MULTICAST
+%token  NUM
+%token  LINK
+%token GEQ LEQ NEQ
+%token ID EID HID
+%token LSH RSH
+%token  LEN
+
+%type  <s> ID
+%type  <e> EID
+%type  <h> HID
+%type  <i> NUM
+
+%left OR AND
+%nonassoc  '!'
+%left '|'
+%left '&' 
+%left LSH RSH
+%left '+' '-'
+%left '*' '/'
+%nonassoc UMINUS
+%%
+prog:    null expr
+{ 
+       finish_parse($2.b);
+}
+       | null
+       ;
+null:    /* null */            { $$.q = qerr; }
+       ;
+expr:    term
+       | expr and term         { gen_and($1.b, $3.b); $$ = $3; }
+       | expr and id           { gen_and($1.b, $3.b); $$ = $3; }
+       | expr or term          { gen_or($1.b, $3.b); $$ = $3; }
+       | expr or id            { gen_or($1.b, $3.b); $$ = $3; }
+       ;
+and:     AND                   { $$ = $<blk>0; }
+       ;
+or:      OR                    { $$ = $<blk>0; }
+       ;
+id:      nid
+       | pnum                  { $$.b = gen_ncode((u_long)$1,
+                                                  $$.q = $<blk>0.q); }
+       | paren pid ')'         { $$ = $2; }
+       ;
+nid:     ID                    { $$.b = gen_scode($1, $$.q = $<blk>0.q); }
+       | HID                   { $$.b = gen_ncode($1, $$.q = $<blk>0.q); }
+       | EID                   { $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
+       | not id                { gen_not($2.b); $$ = $2; }
+       ;
+not:     '!'                   { $$ = $<blk>0; }
+       ;
+paren:   '('                   { $$ = $<blk>0; }
+       ;
+pid:     nid
+       | qid and id            { gen_and($1.b, $3.b); $$ = $3; }
+       | qid or id             { gen_or($1.b, $3.b); $$ = $3; }
+       ;
+qid:     pnum                  { $$.b = gen_ncode((u_long)$1, 
+                                                  $$.q = $<blk>0.q); }
+       | pid
+       ;
+term:    rterm
+       | not term              { gen_not($2.b); $$ = $2; }
+       ;
+head:    pqual dqual aqual     { QSET($$.q, $1, $2, $3); }
+       | pqual dqual           { QSET($$.q, $1, $2, Q_DEFAULT); }
+       | pqual aqual           { QSET($$.q, $1, Q_DEFAULT, $2); }
+       | pqual PROTO           { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
+       | pqual ndaqual         { QSET($$.q, $1, Q_DEFAULT, $2); }
+       ;
+rterm:   head id               { $$ = $2; }
+       | paren expr ')'        { $$.b = $2.b; $$.q = $1.q; }
+       | pname                 { $$.b = gen_proto_abbrev($1); $$.q = qerr; }
+       | arth relop arth       { $$.b = gen_relation($2, $1, $3, 0); 
+                                 $$.q = qerr; }
+       | arth irelop arth      { $$.b = gen_relation($2, $1, $3, 1); 
+                                 $$.q = qerr; }
+       | other                 { $$.b = $1; $$.q = qerr; }
+       ;
+/* protocol level qualifiers */
+pqual:   pname
+       |                       { $$ = Q_DEFAULT; }
+       ;
+/* 'direction' qualifiers */
+dqual:   SRC                   { $$ = Q_SRC; }
+       | DST                   { $$ = Q_DST; }
+       | SRC OR DST            { $$ = Q_OR; }
+       | DST OR SRC            { $$ = Q_OR; }
+       | SRC AND DST           { $$ = Q_AND; }
+       | DST AND SRC           { $$ = Q_AND; }
+       ;
+/* address type qualifiers */
+aqual:   HOST                  { $$ = Q_HOST; }
+       | NET                   { $$ = Q_NET; }
+       | PORT                  { $$ = Q_PORT; }
+       ;
+/* non-directional address type qualifiers */
+ndaqual:  GATEWAY              { $$ = Q_GATEWAY; }
+       ;
+pname:   LINK                  { $$ = Q_LINK; }
+       | IP                    { $$ = Q_IP; }
+       | ARP                   { $$ = Q_ARP; }
+       | RARP                  { $$ = Q_RARP; }
+       | TCP                   { $$ = Q_TCP; }
+       | UDP                   { $$ = Q_UDP; }
+       | ICMP                  { $$ = Q_ICMP; }
+       ;
+other:   pqual TK_BROADCAST    { $$ = gen_broadcast($1); }
+       | pqual TK_MULTICAST    { $$ = gen_multicast($1); }
+       | LESS NUM              { $$ = gen_less($2); }
+       | GREATER NUM           { $$ = gen_greater($2); }
+       | BYTE NUM byteop NUM   { $$ = gen_byteop($3, $2, $4); }
+       ;
+relop:   '>'                   { $$ = BPF_JGT; }
+       | GEQ                   { $$ = BPF_JGE; }
+       | '='                   { $$ = BPF_JEQ; }
+       ;
+irelop:          LEQ                   { $$ = BPF_JGT; }
+       | '<'                   { $$ = BPF_JGE; }
+       | NEQ                   { $$ = BPF_JEQ; }
+       ;
+arth:    pnum                  { $$ = gen_loadi($1); }
+       | narth
+       ;
+narth:   pname '[' arth ']'            { $$ = gen_load($1, $3, 1); }
+       | pname '[' arth ':' NUM ']'    { $$ = gen_load($1, $3, $5); }
+       | arth '+' arth                 { $$ = gen_arth(BPF_ADD, $1, $3); }
+       | arth '-' arth                 { $$ = gen_arth(BPF_SUB, $1, $3); }
+       | arth '*' arth                 { $$ = gen_arth(BPF_MUL, $1, $3); }
+       | arth '/' arth                 { $$ = gen_arth(BPF_DIV, $1, $3); }
+       | arth '&' arth                 { $$ = gen_arth(BPF_AND, $1, $3); }
+       | arth '|' arth                 { $$ = gen_arth(BPF_OR, $1, $3); }
+       | arth LSH arth                 { $$ = gen_arth(BPF_LSH, $1, $3); }
+       | arth RSH arth                 { $$ = gen_arth(BPF_RSH, $1, $3); }
+       | '-' arth %prec UMINUS         { $$ = gen_neg($2); }
+       | paren narth ')'               { $$ = $2; }
+       | LEN                           { $$ = gen_loadlen(); }
+       ;
+byteop:          '&'                   { $$ = '&'; }
+       | '|'                   { $$ = '|'; }
+       | '<'                   { $$ = '<'; }
+       | '>'                   { $$ = '>'; }
+       | '='                   { $$ = '='; }
+       ;
+pnum:    NUM
+       | paren pnum ')'        { $$ = $2; }
+       ;
+%%
diff --git a/usr/src/contrib/tcpdump/tcpdump/tcplex.l b/usr/src/contrib/tcpdump/tcpdump/tcplex.l
new file mode 100644 (file)
index 0000000..840590a
--- /dev/null
@@ -0,0 +1,146 @@
+%{
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: tcplex.l,v 1.26 92/02/14 15:16:35 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * Compiling with gcc under SunOS will cause problems unless we have this
+ * cruft here.  The flex skeleton includes stddef.h which defines these types
+ * (under gcc).  They will conflict with Sun's definitions in sys/types.h.
+ */
+#define size_t xxxsize_t
+#define ptrdiff_t xxxptrdiff_t
+#define wchar_t xxxwchar_t
+#include <sys/types.h>
+#undef size_t
+#undef ptrdiff_t
+#undef wchar_t
+
+#include "nametoaddr.h"
+
+/*
+ * We need bpf since enum bpf_code is in YYSTYPE.
+ */
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "gencode.h"
+#include "y.tab.h" /* "tokdefs.h" */
+
+#ifdef FLEX_SCANNER
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max)\
+ {\
+       char *src = in_buffer;\
+       int i;\
+\
+       if (*src == 0)\
+               result = YY_NULL;\
+       else {\
+               for (i = 0; *src && i < max; ++i)\
+                       buf[i] = *src++;\
+               in_buffer += i;\
+               result = i;\
+       }\
+ }
+#else
+#undef getc
+#define getc(fp)  (*in_buffer == 0 ? EOF : *in_buffer++)
+#endif
+
+extern YYSTYPE yylval;
+static char *in_buffer;
+
+%}
+
+N              ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
+B              ([0-9A-Fa-f][0-9A-Fa-f]?)
+
+%a 3000
+
+%%
+dst            return DST;
+src            return SRC;
+
+link|ether|ppp|slip  return LINK;
+arp            return ARP;
+rarp           return RARP;
+ip             return IP;
+tcp            return TCP;
+udp            return UDP;
+icmp           return ICMP;
+
+host           return HOST;
+net            return NET;
+port           return PORT;
+proto          return PROTO;
+
+gateway                return GATEWAY;
+
+less           return LESS;
+greater                return GREATER;
+byte           return BYTE;
+broadcast      return TK_BROADCAST;
+multicast      return TK_MULTICAST;
+
+and            return AND;
+or             return OR;
+not            return '!';
+
+len            return LEN;
+
+[ \n\t]                        ;
+[+\-*/:\[\]!<>()&|=]   return yytext[0];
+">="                   return GEQ;
+"<="                   return LEQ;
+"!="                   return NEQ;
+"=="                   return '=';
+"<<"                   return LSH;
+">>"                   return RSH;
+{N}                    { yylval.i = stoi(yytext); return NUM; }
+({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N})        { 
+                       yylval.h = atoin(yytext); return HID;
+}
+{B}:{B}:{B}:{B}:{B}:{B} { yylval.e = ETHER_aton(yytext); return EID; }
+{B}:+({B}:+)+          { error("bogus ethernet address %s", yytext); }
+[A-Za-z][-_.A-Za-z0-9]*        { yylval.s = yytext; return ID; }
+"\\"[^ !()\n\t]+       { yylval.s = yytext + 1; return ID; }
+[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+    { error("illegal token: %s\n", yytext); }
+.                      { error("illegal char '%c'", *yytext); }
+%%
+void
+lex_init(buf)
+       char *buf;
+{
+       in_buffer = buf;
+}
+#ifndef FLEX_SCANNER
+int 
+yywrap()
+/* so we don't need -ll */
+{
+       return 1;
+}                              
+#endif
diff --git a/usr/src/contrib/tcpdump/tcpdump/util.c b/usr/src/contrib/tcpdump/tcpdump/util.c
new file mode 100644 (file)
index 0000000..ec58c3f
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 1988-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Header: util.c,v 1.12 91/10/28 22:09:31 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <varargs.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "interface.h"
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+       if (isdigit(c))
+               return c - '0';
+       else if (islower(c))
+               return c - 'a' + 10;
+       else
+               return c - 'A' + 10;
+}
+
+/*
+ * Convert string to integer.  Just like atoi(), but checks for 
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ */
+int
+stoi(s)
+       char *s;
+{
+       int base = 10;
+       int n = 0;
+
+       if (*s == '0') {
+               if (s[1] == 'x' || s[1] == 'X') {
+                       s += 2;
+                       base = 16;
+               }
+               else {
+                       base = 8;
+                       s += 1;
+               }
+       }
+       while (*s)
+               n = n * base + xdtoi(*s++);
+
+       return n;
+}
+
+/*
+ * Print out a filename (or other ascii string).
+ * Return true if truncated.
+ */
+int
+printfn(s, ep)
+       register u_char *s, *ep;
+{
+       register u_char c;
+
+       putchar('"');
+       while (c = *s++) {
+               if (s > ep) {
+                       putchar('"');
+                       return(1);
+               }
+               if (!isascii(c)) {
+                       c = toascii(c);
+                       putchar('M');
+                       putchar('-');
+               }
+               if (!isprint(c)) {
+                       c ^= 0x40;      /* DEL to ?, others to alpha */
+                       putchar('^');
+               }
+               putchar(c);
+       }
+       putchar('"');
+       return(0);
+}
+
+/*
+ * Print the timestamp
+ */
+void
+ts_print(tvp)
+       register struct timeval *tvp;
+{
+       register int i;
+
+       if (tflag > 0) {
+               /* Default */
+               i = (tvp->tv_sec + thiszone) % 86400;
+               (void)printf("%02d:%02d:%02d.%06d ",
+                   i / 3600, (i % 3600) / 60, i % 60, tvp->tv_usec);
+       } else if (tflag < 0) {
+               /* Unix timeval style */
+               (void)printf("%d.%06d ", tvp->tv_sec, tvp->tv_usec);
+       }
+}
+
+#ifdef NOVFPRINTF
+/*
+ * Stock 4.3 doesn't have vfprintf. 
+ * This routine is due to Chris Torek.
+ */
+vfprintf(f, fmt, args)
+       FILE *f;
+       char *fmt;
+       va_list args;
+{
+       int ret;
+
+       if ((f->_flag & _IOWRT) == 0) {
+               if (f->_flag & _IORW)
+                       f->_flag |= _IOWRT;
+               else
+                       return EOF;
+       }
+       ret = _doprnt(fmt, args, f);
+       return ferror(f) ? EOF : ret;
+}
+#endif
+
+static char *
+stripdir(s)
+       register char *s;
+{
+       register char *cp;
+       char *rindex();
+
+       cp = rindex(s, '/');
+       return (cp != 0) ? cp + 1 : s;
+}
+
+/* VARARGS */
+void
+error(va_alist)
+       va_dcl
+{
+       register char *cp;
+       va_list ap;
+
+       (void)fprintf(stderr, "%s: ", stripdir(program_name));
+
+       va_start(ap);
+       cp = va_arg(ap, char *);
+       (void)vfprintf(stderr, cp, ap);
+       va_end(ap);
+       if (*cp) {
+               cp += strlen(cp);
+               if (cp[-1] != '\n')
+                       (void)fputc('\n', stderr);
+       }
+       exit(1);
+       /* NOTREACHED */
+}
+
+/* VARARGS */
+void
+warning(va_alist)
+       va_dcl
+{
+       register char *cp;
+       va_list ap;
+
+       (void)fprintf(stderr, "%s: warning: ", stripdir(program_name));
+
+       va_start(ap);
+       cp = va_arg(ap, char *);
+       (void)vfprintf(stderr, cp, ap);
+       va_end(ap);
+       if (*cp) {
+               cp += strlen(cp);
+               if (cp[-1] != '\n')
+                       (void)fputc('\n', stderr);
+       }
+}
+
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+char *
+copy_argv(argv)
+       register char **argv;
+{
+       register char **p;
+       register int len = 0;
+       char *buf;
+       char *src, *dst;
+
+       p = argv;
+       if (*p == 0)
+               return 0;
+
+       while (*p)
+               len += strlen(*p++) + 1;
+
+       buf = malloc(len);
+
+       p = argv;
+       dst = buf;
+       while (src = *p++) {
+               while (*dst++ = *src++)
+                       ;
+               dst[-1] = ' ';
+       }
+       dst[-1] = '\0';
+
+       return buf;
+}
+
+char *
+read_infile(fname)
+       char *fname;
+{
+       struct stat buf;
+       int fd;
+       char *p;
+
+       fd = open(fname, O_RDONLY);
+       if (fd < 0)
+               error("can't open '%s'", fname);
+
+       if (fstat(fd, &buf) < 0)
+               error("can't state '%s'", fname);
+
+       p = malloc((unsigned)buf.st_size);
+       if (read(fd, p, (int)buf.st_size) != buf.st_size)
+               error("problem reading '%s'", fname);
+       
+       return p;
+}
+
+/*
+ * Left justify 'addr' and return its resulting network mask.
+ */
+u_long
+net_mask(addr)
+       u_long *addr;
+{
+       register u_long m = 0xffffffff;
+
+       if (*addr)
+               while ((*addr & 0xff000000) == 0)
+                       *addr <<= 8, m <<= 8;
+
+       return m;
+}
diff --git a/usr/src/contrib/tcpdump/tcpslice/Makefile b/usr/src/contrib/tcpdump/tcpslice/Makefile
new file mode 100644 (file)
index 0000000..d1cd63b
--- /dev/null
@@ -0,0 +1,18 @@
+#      @(#)Makefile    0.1 (RWGrimes) 3/24/93
+
+PROG=  tcpslice
+CFLAGS+=-DCSLIP -I. -I$(.CURDIR)/../tcpdump
+MAN1=  tcpslice.0
+SRCS=  version.c tcpslice.c gwtm2secs.c search.c \
+       savefile.c bpf_filter.c md.c util.c
+.PATH: ${.CURDIR}/../tcpdump /sys/net
+CLEANFILES+=   version.c version.h
+
+version.c version.h: $(.CURDIR)/../tcpdump/VERSION
+       rm -f version.c ; \
+       sed 's/.*/char version[] = "&";/' $(.CURDIR)/../tcpdump/VERSION > version.c
+       set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/../tcpdump/VERSION` ; \
+               { echo '#define VERSION_MAJOR' $$1 ; \
+                 echo '#define VERSION_MINOR' $$2 ; } > version.h
+
+.include <bsd.prog.mk>
diff --git a/usr/src/contrib/tcpdump/tcpslice/gwtm2secs.c b/usr/src/contrib/tcpdump/tcpslice/gwtm2secs.c
new file mode 100644 (file)
index 0000000..aeb377f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#)$Header: gwtm2secs.c,v 1.1 92/06/02 11:35:19 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * gwtm2secs.c - convert "tm" structs for Greenwich time to Unix timestamp
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+
+static int days_in_month[] =
+       /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
+       {  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+#define IS_LEAP_YEAR(year)     \
+       (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+
+time_t gwtm2secs( tm )
+struct tm *tm;
+       {
+       int i, days, year;
+
+       year = tm->tm_year;
+
+       /* Allow for year being specified with either 2 digits or 4 digits.
+        * 2-digit years are either 19xx or 20xx - a simple heuristic
+        * distinguishes them, since we can't represent any time < 1970.
+        */
+       if ( year < 100 )
+               if ( year >= 70 )
+                       year += 1900;
+               else
+                       year += 2000;
+
+       days = 0;
+       for ( i = 1970; i < year; ++i )
+               {
+               days += 365;
+               if ( IS_LEAP_YEAR(i) )
+                       ++days;
+               }
+
+       for ( i = 0; i < tm->tm_mon; ++i )
+               days += days_in_month[i];
+
+       if ( IS_LEAP_YEAR(year) && tm->tm_mon > 1 ) /* 1 is February */
+               ++days;
+
+       days += tm->tm_mday - 1; /* -1 since days are numbered starting at 1 */
+
+       return days * 86400 + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+       }
diff --git a/usr/src/contrib/tcpdump/tcpslice/search.c b/usr/src/contrib/tcpdump/tcpslice/search.c
new file mode 100644 (file)
index 0000000..8bea0d2
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+static char rcsid[] =
+    "@(#)$Header: search.c,v 1.3 92/05/01 15:14:45 vern Exp $ (LBL)";
+#endif
+
+/*
+ * search.c - supports fast searching through tcpdump files for timestamps
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "interface.h"
+#include "savefile.h"
+
+
+/* Maximum number of seconds that we can conceive of a dump file spanning. */
+#define MAX_REASONABLE_FILE_SPAN (3600*24*366) /* one year */
+
+/* Maximum packet length we ever expect to see. */
+#define MAX_REASONABLE_PACKET_LENGTH 65535
+
+/* Size of a packet header in bytes; easier than typing the sizeof() all
+ * the time ...
+ */
+#define PACKET_HDR_LEN (sizeof( struct packet_header ))
+
+/* The maximum size of a packet, including its header. */
+#define MAX_PACKET_SIZE (PACKET_HDR_LEN + snaplen)
+
+/* Number of contiguous bytes from a dumpfile in which there's guaranteed
+ * to be enough information to find a "definite" header if one exists
+ * therein.  This takes 3 full packets - the first to be just misaligned
+ * (one byte short of a full packet), missing its timestamp; the second
+ * to have the legitimate timestamp; and the third to provide confirmation
+ * that the second is legit, making it a "definite" header.  We could
+ * scrimp a bit here since not the entire third packet is required, but
+ * it doesn't seem worth it
+ */
+#define MAX_BYTES_FOR_DEFINITE_HEADER (3 * MAX_PACKET_SIZE)
+
+/* Maximum number of seconds that might reasonably separate two headers. */
+#define MAX_REASONABLE_HDR_SEPARATION (3600 * 24 * 7)  /* one week */
+
+/* When searching a file for a packet, if we think we're within this many
+ * bytes of the packet we just search linearly.  Since linear searches are
+ * probably much faster than random ones (random ones require searching for
+ * the beginning of the packet, which may be unaligned in memory), we make
+ * this value pretty hefty.
+ */
+#define STRAIGHT_SCAN_THRESHOLD (100 * MAX_PACKET_SIZE)
+
+/* Extracts a long integer from a possibly unaligned buffer containing
+ * unsigned characters.
+ */
+#define EXTRACT_LONG(buf) (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3])
+
+
+/* Given a header and an acceptable first and last time stamp, returns non-zero
+ * if the header looks reasonable and zero otherwise.
+ */
+static int reasonable_header( hdr, first_time, last_time )
+struct packet_header *hdr;
+long first_time, last_time;
+       {
+       if ( last_time == 0 )
+               last_time = first_time + MAX_REASONABLE_FILE_SPAN;
+
+       return hdr->ts.tv_sec >= first_time &&
+              hdr->ts.tv_sec <= last_time &&
+              hdr->len > 0 &&
+              hdr->len <= MAX_REASONABLE_PACKET_LENGTH &&
+              hdr->caplen > 0 &&
+              hdr->caplen <= MAX_REASONABLE_PACKET_LENGTH;
+       }
+
+
+/* Given a buffer, extracts a (properly aligned) packet header from it. */
+
+static void extract_header( buf, hdr )
+u_char *buf;
+struct packet_header *hdr;
+       {
+       hdr->ts.tv_sec = EXTRACT_LONG(buf);
+       buf += sizeof( long );
+       hdr->ts.tv_usec = EXTRACT_LONG(buf);
+       buf += sizeof( long );
+       hdr->len = EXTRACT_LONG(buf);
+       buf += sizeof( long );
+       hdr->caplen = EXTRACT_LONG(buf);
+
+       if ( sf_swapped )
+               {
+               hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
+               hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
+               hdr->len = SWAPLONG(hdr->len);
+               hdr->caplen = SWAPLONG(hdr->caplen);
+               }
+       }
+
+
+/* Search a buffer to locate the first header within it.  Return values
+ * are HEADER_NONE, HEADER_CLASH, HEADER_PERHAPS, and HEADER_DEFINITELY.
+ * The first indicates that no evidence of a header was found; the second
+ * that two or more possible headers were found, neither more convincing
+ * than the other(s); the third that exactly one "possible" header was
+ * found; and the fourth that exactly one "definite" header was found.
+ *
+ * Headers are detected by looking for positions in the buffer which have
+ * reasonable timestamps and lengths.  If there is enough room in the buffer
+ * for another header to follow a candidate header, a check is made for
+ * that following header.  If it is present then the header is *definite*
+ * (unless another "perhaps" or "definite" header is found); if not, then
+ * the header is discarded.  If there is not enough room in the buffer for
+ * another header then the candidate is *perhaps* (unless another header
+ * is subsequently found).  A "tie" between a "definite" header and a
+ * "perhaps" header is resolved in favor of the definite header.  Any
+ * other tie leads to HEADER_CLASH.
+ *
+ * The buffer position of the header is returned in hdrpos_addr and
+ * for convenience the corresponding header in return_hdr.
+ *
+ * first_time is the earliest possible acceptable timestamp in the
+ * header.  last_time, if non-zero, is the last such timestamp.  If
+ * zero, then up to MAX_REASONABLE_FILE_SPAN seconds after first_time
+ * is acceptable.
+ */
+
+#define HEADER_NONE 0
+#define HEADER_CLASH 1
+#define HEADER_PERHAPS 2
+#define HEADER_DEFINITELY 3
+
+static int find_header( buf, buf_len, first_time, last_time,
+                hdrpos_addr, return_hdr )
+u_char *buf;
+unsigned buf_len;
+long first_time, last_time;
+u_char **hdrpos_addr;
+struct packet_header *return_hdr;
+       {
+       u_char *bufptr, *bufend, *last_pos_to_try;
+       struct packet_header hdr, hdr2;
+       int status = HEADER_NONE;
+       int saw_PERHAPS_clash = 0;
+
+       /* Initially, try each buffer position to see whether it looks like
+        * a valid packet header.  We may later restrict the positions we look
+        * at to avoid seeing a sequence of legitimate headers as conflicting
+        * with one another.
+        */
+       bufend = buf + buf_len;
+       last_pos_to_try = bufend - PACKET_HDR_LEN;
+
+       for ( bufptr = buf; bufptr < last_pos_to_try; ++bufptr )
+           {
+           extract_header( bufptr, &hdr );
+
+           if ( reasonable_header( &hdr, first_time, last_time ) )
+               {
+               u_char *next_header = bufptr + PACKET_HDR_LEN + hdr.caplen;
+
+               if ( next_header + PACKET_HDR_LEN < bufend )
+                   { /* check for another good header */
+                   extract_header( next_header, &hdr2 );
+
+                   if ( reasonable_header( &hdr2, hdr.ts.tv_sec, 
+                           hdr.ts.tv_sec + MAX_REASONABLE_HDR_SEPARATION ) )
+                       { /* a confirmed header */
+                       switch ( status )
+                           {
+                           case HEADER_NONE:
+                           case HEADER_PERHAPS:
+                               status = HEADER_DEFINITELY;
+                               *hdrpos_addr = bufptr;
+                               *return_hdr = hdr;
+
+                               /* Make sure we don't demote this "definite"
+                                * to a "clash" if we stumble across its
+                                * successor.
+                                */
+                               last_pos_to_try = next_header - PACKET_HDR_LEN;
+                               break;
+
+                           case HEADER_DEFINITELY:
+                               return HEADER_CLASH;
+
+                           default:
+                               error( "bad status in find_header()" );
+                           }
+                       }
+
+                   /* ... else the header is bogus - we've verified that it's
+                    * not followed by a reasonable header.
+                    */
+                   }
+
+               else
+                   { /* can't check for another good header */
+                   switch ( status )
+                       {
+                       case HEADER_NONE:
+                           status = HEADER_PERHAPS;
+                           *hdrpos_addr = bufptr;
+                           *return_hdr = hdr;
+                           break;
+
+                       case HEADER_PERHAPS:
+                           /* We don't immediately turn this into a
+                            * clash because perhaps we'll later see a
+                            * "definite" which will save us ...
+                            */
+                           saw_PERHAPS_clash = 1;
+                           break;
+
+                       case HEADER_DEFINITELY:
+                           /* Keep the definite in preference to this one. */
+                           break;
+
+                       default:
+                           error( "bad status in find_header()" );
+                       }
+                   }
+               }
+           }
+
+       if ( status == HEADER_PERHAPS && saw_PERHAPS_clash )
+               status = HEADER_CLASH;
+
+       return status;
+       }
+
+
+/* Positions the sf_readfile stream such that the next sf_read() will
+ * read the final full packet in the file.  Returns non-zero if
+ * successful, zero if unsuccessful.  If successful, returns the
+ * timestamp of the last packet in last_timestamp.
+ *
+ * Note that this routine is a special case of sf_find_packet().  In
+ * order to use sf_find_packet(), one first must use this routine in
+ * order to give sf_find_packet() an upper bound on the timestamps
+ * present in the dump file.
+ */
+int sf_find_end( first_timestamp, last_timestamp )
+struct timeval *first_timestamp;
+struct timeval *last_timestamp;
+       {
+       long first_time = first_timestamp->tv_sec;
+       unsigned num_bytes;
+       u_char *buf, *bufpos, *bufend;
+       u_char *hdrpos;
+       struct packet_header hdr, successor_hdr;
+       int status;
+
+       /* Allow enough room for at least two full (untruncated) packets,
+        * perhaps followed by a truncated packet, so we have a shot at
+        * finding a "definite" header and following its chain to the
+        * end of the file.
+        */
+       num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER;
+       if ( fseek( sf_readfile, (long) -num_bytes, 2 ) < 0 )
+               return 0;
+
+       buf = (u_char *)malloc((unsigned) num_bytes);
+       if ( ! buf )
+               return 0;
+
+       status = 0;
+       bufpos = buf;
+       bufend = buf + num_bytes;
+
+       if ( fread( (char *) bufpos, num_bytes, 1, sf_readfile ) != 1 )
+               goto done;
+
+       if ( find_header( bufpos, num_bytes, first_time, 0L, &hdrpos, &hdr ) !=
+            HEADER_DEFINITELY )
+               goto done;
+
+       /* Okay, we have a definite header in our hands.  Follow its
+        * chain till we find the last valid packet in the file ...
+        */
+       for ( ; ; )
+               {
+               /* move to the next header position */
+               bufpos = hdrpos + PACKET_HDR_LEN + hdr.caplen;
+
+               /* bufpos now points to a candidate packet, which if valid
+                * should replace the current packet pointed to by hdrpos as
+                * the last valid packet ...
+                */
+               if ( bufpos >= bufend - PACKET_HDR_LEN )
+                       /* not enough room for another header */
+                       break;
+
+               extract_header( bufpos, &successor_hdr );
+
+               first_time = hdr.ts.tv_sec;
+               if ( ! reasonable_header( &successor_hdr, first_time, 0L ) )
+                       /* this bodes ill - it means bufpos is perhaps a
+                        * bogus packet header after all ...
+                        */
+                       break;
+
+               /* Note that the following test is for whether the next
+                * packet starts at a position > bufend, *not* for a
+                * position >= bufend.  If this is the last packet in the
+                * file and there isn't a subsequent partial packet, then
+                * we expect the first buffer position beyond this packet
+                * to be just beyond the end of the buffer, i.e., at bufend
+                * itself.
+                */
+               if ( bufpos + PACKET_HDR_LEN + successor_hdr.caplen > bufend )
+                       /* the packet is truncated */
+                       break;
+
+               /* Accept this packet as fully legit. */
+               hdrpos = bufpos;
+               hdr = successor_hdr;
+               }
+
+       /* Success!  Last valid packet is at hdrpos. */
+       *last_timestamp = hdr.ts;
+       status = 1;
+
+       /* Seek so that the next read will start at last valid packet. */
+       if ( fseek( sf_readfile, (long) -(bufend - hdrpos), 2 ) < 0 )
+               error( "final fseek() failed in sf_find_end()" );
+
+    done:
+       free( (char *) buf );
+
+       return status;
+       }
+
+
+/* Takes two timeval's and returns the difference, tv2 - tv1, as a double. */
+
+static double timeval_diff( tv1, tv2 )
+struct timeval *tv1, *tv2;
+       {
+       double result = (tv2->tv_sec - tv1->tv_sec);
+       result += (tv2->tv_usec - tv1->tv_usec) / 1000000.0;
+
+       return result;
+       }
+
+
+/* Returns true if timestamp t1 is chronologically less than timestamp t2. */
+
+int sf_timestamp_less_than( t1, t2 )
+struct timeval *t1, *t2;
+       {
+       return t1->tv_sec < t2->tv_sec ||
+              (t1->tv_sec == t2->tv_sec &&
+               t1->tv_usec < t2->tv_usec);
+       }
+
+
+/* Given two timestamps on either side of desired_time and their positions,
+ * returns the interpolated position of the desired_time packet.  Returns a
+ * negative value if the desired_time is outside the given range.
+ */
+
+static
+long interpolated_position( min_time, min_pos, max_time, max_pos, desired_time )
+struct timeval *min_time, *max_time, *desired_time;
+long min_pos, max_pos;
+       {
+       double full_span = timeval_diff( max_time, min_time );
+       double desired_span = timeval_diff( desired_time, min_time );
+       long full_span_pos = max_pos - min_pos;
+       double fractional_offset = desired_span / full_span;
+
+       if ( fractional_offset < 0.0 || fractional_offset > 1.0 )
+               return -1;
+
+       return min_pos + (long) (fractional_offset * (double) full_span_pos);
+       }
+
+
+/* Reads packets linearly until one with a time >= the given desired time
+ * is found; positions the dump file so that the next read will start
+ * at the given packet.  Returns non-zero on success, 0 if an EOF was
+ * first encountered.
+ */
+
+static int read_up_to( desired_time )
+struct timeval *desired_time;
+       {
+       int status = 1;
+       struct packet_header hdr;
+       u_char *buf;
+       long pos;
+
+       buf = (u_char *) malloc( (unsigned) snaplen );
+
+       for ( ; ; )
+               {
+               struct timeval *timestamp;
+
+               pos = ftell( sf_readfile );
+               status = sf_next_packet( &hdr, buf, snaplen );
+
+               if ( status )
+                       {
+                       if ( status == SFERR_EOF )
+                               {
+                               status = 0;
+                               break;
+                               }
+
+                       error( "bad status %d in read_up_to()", status );
+                       }
+
+               timestamp = &hdr.ts;
+
+               if ( ! sf_timestamp_less_than( timestamp, desired_time ) )
+                       break;
+               }
+
+       if ( fseek( sf_readfile, pos, 0 ) < 0 )
+               error( "fseek() failed in read_up_to()" );
+
+       free( (char *) buf );
+
+       return status;
+       }
+
+
+/* Positions the sf_readfile stream so that the next sf_read() will
+ * return the first packet with a time greater than or equal to
+ * desired_time.  desired_time must be greater than min_time and less
+ * than max_time, which should correspond to actual packets in the
+ * file.  min_pos is the file position (byte offset) corresponding to
+ * the min_time packet and max_pos is the same for the max_time packet.
+ *
+ * Returns non-zero on success, 0 if the given position is beyond max_pos.
+ *
+ * NOTE: when calling this routine, the sf_readfile stream *must* be
+ * already aligned so that the next call to sf_next_packet() will yield
+ * a valid packet.
+ */
+
+int sf_find_packet( min_time, min_pos, max_time, max_pos, desired_time )
+struct timeval *min_time, *max_time;
+long min_pos, max_pos;
+struct timeval *desired_time;
+       {
+       int status = 1;
+       struct timeval min_time_copy, max_time_copy;
+       unsigned num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER;
+       int num_bytes_read;
+       long desired_pos, present_pos;
+       u_char *buf, *hdrpos;
+       struct packet_header hdr;
+
+       buf = (u_char *) malloc( num_bytes );
+       if ( ! buf )
+               error( "malloc() failured in sf_find_packet()" );
+
+       min_time_copy = *min_time;
+       min_time = &min_time_copy;
+
+       max_time_copy = *max_time;
+       max_time = &max_time_copy;
+
+       for ( ; ; )     /* loop until positioned correctly */
+               {
+               desired_pos =
+                       interpolated_position( min_time, min_pos,
+                                              max_time, max_pos,
+                                              desired_time );
+
+               if ( desired_pos < 0 )
+                       {
+                       status = 0;
+                       break;
+                       }
+
+               present_pos = ftell( sf_readfile );
+
+               if ( present_pos <= desired_pos &&
+                    desired_pos - present_pos < STRAIGHT_SCAN_THRESHOLD )
+                       { /* we're close enough to just blindly read ahead */
+                       status = read_up_to( desired_time );
+                       break;
+                       }
+
+               /* Undershoot the target a little bit - it's much easier to
+                * then scan straight forward than to try to read backwards ...
+                */
+               desired_pos -= STRAIGHT_SCAN_THRESHOLD / 2;
+               if ( desired_pos < min_pos )
+                       desired_pos = min_pos;
+
+               if ( fseek( sf_readfile, desired_pos, 0 ) < 0 )
+                       error( "fseek() failed in sf_find_packet()" );
+
+               num_bytes_read =
+                       fread( (char *) buf, 1, num_bytes, sf_readfile );
+
+               if ( num_bytes_read == 0 )
+                       /* This shouldn't ever happen because we try to
+                        * undershoot, unless the dump file has only a
+                        * couple packets in it ...
+                        */
+                       error( "fread() failed in sf_find_packet()" );
+
+               if ( find_header( buf, num_bytes, min_time->tv_sec,
+                                 max_time->tv_sec, &hdrpos, &hdr ) !=
+                    HEADER_DEFINITELY )
+                       error( "can't find header at position %ld in dump file",
+                               desired_pos );
+
+               /* Correct desired_pos to reflect beginning of packet. */
+               desired_pos += (hdrpos - buf);
+
+               /* Seek to the beginning of the header. */
+               if ( fseek( sf_readfile, desired_pos, 0 ) < 0 )
+                       error( "fseek() failed in sf_find_packet()" );
+
+               if ( sf_timestamp_less_than( &hdr.ts, desired_time ) )
+                       { /* too early in the file */
+                       *min_time = hdr.ts;
+                       min_pos = desired_pos;
+                       }
+
+               else if ( sf_timestamp_less_than( desired_time, &hdr.ts ) )
+                       { /* too late in the file */
+                       *max_time = hdr.ts;
+                       max_pos = desired_pos;
+                       }
+
+               else
+                       /* got it! */
+                       break;
+               }
+
+       free( (char *) buf );
+
+       return status;
+       }
diff --git a/usr/src/contrib/tcpdump/tcpslice/tcpslice.1 b/usr/src/contrib/tcpdump/tcpslice/tcpslice.1
new file mode 100644 (file)
index 0000000..b130f2c
--- /dev/null
@@ -0,0 +1,260 @@
+.\" @(#) $Header: tcpslice.1,v 1.2 91/10/16 11:42:46 vern Exp $ (LBL)
+.\"
+.\" Copyright (c) 1988-1990 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: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH TCPSLICE 1  "14 Oct 1991"
+.SH NAME
+tcpslice \- extract pieces of and/or glue together tcpdump files
+.SH SYNOPSIS
+.na
+.B tcpslice
+[
+.B \-dRrt
+] [
+.B \-w
+.I file
+]
+.br
+.ti +9
+[
+.I start-time
+[
+.I end-time
+] ]
+.I file ...
+.br
+.ad
+.SH DESCRIPTION
+.LP
+.I Tcpslice
+is a program for extracting portions of packet-trace files generated using
+\fItcpdump(l)\fP's
+.B \-w
+flag.
+It can also be used to glue together several such files, as discussed
+below.
+.LP
+The basic operation of
+.I tcpslice
+is to copy to
+.I stdout
+all packets from its input file(s) whose timestamps fall
+within a given range.  The starting and ending times of the range
+may be specified on the command line.  All ranges are inclusive.
+The starting time defaults
+to the time of the first packet in the first input file; we call
+this the
+.I first time.
+The ending time defaults to ten years after the starting time.
+Thus, the command
+.I tcpslice trace-file
+simply copies
+.I trace-file
+to \fIstdout\fP (assuming the file does not include more than
+ten years' worth of data).
+.LP
+There are a number of ways to specify times.  The first is using
+Unix timestamps of the form
+.I sssssssss.uuuuuu
+(this is the format specified by \fItcpdump\fP's
+.B \-tt
+flag).
+For example,
+.B 654321098.7654
+specifies 38 seconds and 765,400 microseconds
+after 8:51PM PDT, Sept. 25, 1990.
+.LP
+All examples in this manual are given
+for PDT times, but when displaying times and interpreting times symbolically
+as discussed below,
+.I tcpslice
+uses the local timezone, regardless of the timezone in which the \fItcpdump\fP
+file was generated.  The daylight-savings setting used is that which is
+appropriate for the local timezone at the date in question.  For example,
+times associated with summer months will usually include daylight-savings
+effects, and those with winter months will not.
+.LP
+Times may also be specified relative
+to either the
+.I first time
+(when specifying a starting time)
+or the starting time (when specifying an ending time)
+by preceding a numeric value in seconds with a `+'.
+For example, a starting time of
+.B +200
+indicates 200 seconds after the
+.I first time,
+and the two arguments
+.B +200 +300
+indicate from 200 seconds after the
+.I first time
+through 500 seconds after the
+.I first time.
+.LP
+Times may also be specified in terms of years (y), months (m), days (d),
+hours (h), minutes (m), seconds (s), and microseconds(u).  For example,
+the Unix timestamp 654321098.7654 discussed above could also be expressed
+as
+.B 90y9m25d20h51m38s765400u.
+.LP
+When specifying times using this style, fields that are omitted default
+as follows.  If the omitted field is a unit
+.I greater
+than that of the first specified field, then its value defaults to
+the corresponding value taken from either
+.I first time
+(if the starting time is being specified) or the starting time
+(if the ending time is being specified).
+If the omitted field is a unit
+.I less
+than that of the first specified field, then it defaults to zero.
+For example, suppose that the input file has a
+.I first time
+of the Unix timestamp mentioned above, i.e., 38 seconds and 765,400 microseconds
+after 8:51PM PDT, Sept. 25, 1990.  To specify 9:36PM PDT (exactly) on the
+same date we could use
+.B 21h36m.
+To specify a range from 9:36PM PDT through 1:54AM PDT the next day we
+could use
+.B 21h36m 26d1h54m.
+.LP
+Relative times can also be specified when using the
+.I ymdhmsu
+format.  Omitted fields then default to 0 if the unit of the field is
+.I greater
+than that of the first specified field, and to the corresponding value
+taken from either the
+.I first time
+or the starting time if the omitted field's unit is
+.I less
+than that of the first specified field.  Given a
+.I first time
+of the Unix timestamp mentioned above,
+.B 22h +1h10m
+specifies a range from 10:00PM PDT on that date through 11:10PM PDT, and
+.B +1h +1h10m
+specifies a range from 38.7654 seconds after 9:51PM PDT through 38.7654
+seconds after 11:01PM PDT.  The first hour of the file could be extracted
+using
+.B +0 +1h.
+.LP
+Note that with the
+.I ymdhmsu
+format there is an ambiguity between using
+.I m
+for `month' or for `minute'.  The ambiguity is resolved as follows: if an
+.I m
+field is followed by a
+.I d
+field then it is interpreted as specifying months; otherwise it
+specifies minutes.
+.LP
+If more than one input file is specified then
+.I tcpslice
+first copies packets lying in the given range from the first file; it
+then increases the starting time of the range to lie just beyond the
+timestamp of the last packet in the first file, repeats the process
+with the second file, and so on.  Thus files with interleaved packets
+are
+.I not
+merged.  For a given file, only packets that are newer than any in the
+preceding files will be considered.  This mechanism avoids any possibility
+of a packet occurring more than once in the output.
+.SH OPTIONS
+.LP
+If any of
+.B \-R,
+.B \-r
+or
+.B \-t
+are specified then
+.I tcpslice
+reports the timestamps of the first and last packets in each input file
+and exits.  Only one of these three options may be specified.
+.TP
+.B \-d
+Dump the start and end times specified by the given range and
+exit.  This option is useful for checking that the given range actually
+specifies the times you think it does.  If one of
+.B \-R,
+.B \-r
+or
+.B \-t
+has been specified then the times are dumped in the corresponding
+format; otherwise, raw format (\fB \-R\fP) is used.
+.TP
+.B \-R
+Dump the timestamps of the first and last packets in each input file
+as raw timestamps (i.e., in the form \fI sssssssss.uuuuuu\fP).
+.TP
+.B \-r
+Same as
+.B \-R
+except the timestamps are dumped in human-readable format, similar
+to that used by \fI date(1)\fP.
+.TP
+.B \-t
+Same as
+.B \-R
+except the timestamps are dumped in
+.I tcpslice
+format, i.e., in the
+.I ymdhmsu
+format discussed above.
+.TP
+.B \-w
+Direct the output to \fIfile\fR rather than \fIstdout\fP.
+.SH "SEE ALSO"
+tcpdump(l)
+.SH AUTHOR
+Vern Paxson (vern@ee.lbl.gov), of
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
+.SH BUGS
+An input filename that beings with a digit or a `+' can be confused
+with a start/end time.  Such filenames can be specified with a
+leading `./'; for example, specify the file `04Jul76.trace' as
+`./04Jul76.trace'.
+.LP
+.I tcpslice
+cannot read its input from \fIstdin\fP, since it uses random-access
+to rummage through its input files.
+.LP
+.I tcpslice
+refuses to write to its output if it is a terminal
+(as indicated by \fIisatty(3)\fP).  This is not a bug but a feature,
+to prevent it from spraying binary data to the user's terminal.
+Note that this means you must either redirect \fIstdout\fP or specify an
+output file via \fB\-w\fP.
+.LP
+.I tcpslice
+will not work properly on \fItcpdump\fP files spanning more than one year;
+with files containing portions of packets whose original length was
+more than 65,535 bytes; nor with files containing fewer than three packets.
+Such files result in
+the error message: `couldn't find final packet in file'.  These problems
+are due to the interpolation scheme used by
+.I tcpslice
+to greatly speed up its processing when dealing with large trace files.
+Note that
+.I tcpslice
+can efficiently extract slices from the middle of trace files of any
+size, and can also work with truncated trace files (i.e., the final packet
+in the file is only partially present, typically due to \fItcpdump\fP
+being ungracefully killed).
diff --git a/usr/src/contrib/tcpdump/tcpslice/tcpslice.c b/usr/src/contrib/tcpdump/tcpslice/tcpslice.c
new file mode 100644 (file)
index 0000000..b5b6eea
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ * Copyright (c) 1987-1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef lint
+char copyright[] =
+    "@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
+static  char rcsid[] =
+    "@(#)$Header: tcpslice.c,v 1.10 92/06/02 17:57:44 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * tcpslice - extract pieces of and/or glue together tcpdump files
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <netinet/in.h>
+#include <varargs.h>
+
+#include "savefile.h"
+#include "version.h"
+
+
+int tflag = 0; /* global that util routines are sensitive to */
+
+char *program_name;
+
+long thiszone;                 /* gmt to local correction in trace file */
+
+/* Length of saved portion of packet. */
+int snaplen;
+
+/* Length of saved portion of data past link level protocol.  */
+int snapdlen;
+
+/* Precision of clock used to generate trace file. */
+int precision;
+
+static int linkinfo;
+
+/* Style in which to print timestamps; RAW is "secs.usecs"; READABLE is
+ * ala the Unix "date" tool; and PARSEABLE is tcpslice's custom format,
+ * designed to be easy to parse.  The default is RAW.
+ */
+enum stamp_styles { TIMESTAMP_RAW, TIMESTAMP_READABLE, TIMESTAMP_PARSEABLE };
+enum stamp_styles timestamp_style = TIMESTAMP_RAW;
+
+
+time_t gwtm2secs( /* struct tm *tmp */ );
+
+
+long local_time_zone( /* timestamp */ );
+struct timeval parse_time(/* time_string, base_time*/);
+void fill_tm(/* time_string, is_delta, t, usecs_addr */);
+void get_file_range( /* filename, first_time, last_time */ );
+struct timeval first_packet_time(/* filename */);
+void extract_slice(/* filename, start_time, stop_time */);
+char *timestamp_to_string( /* timestamp */ );
+void dump_times(/* filename */);
+void usage();
+
+
+int
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       int op;
+       int dump_flag = 0;
+       int report_times = 0;
+       char *start_time_string = 0;
+       char *stop_time_string = 0;
+       char *write_file_name = "-";    /* default is stdout */
+       struct timeval first_time, start_time, stop_time;
+
+       extern char *optarg;
+       extern int optind, opterr;
+
+       program_name = argv[0];
+
+       opterr = 0;
+       while ((op = getopt(argc, argv, "dRrtw:")) != EOF)
+               switch (op) {
+
+               case 'd':
+                       dump_flag = 1;
+                       break;
+
+               case 'R':
+                       ++report_times;
+                       timestamp_style = TIMESTAMP_RAW;
+                       break;
+
+               case 'r':
+                       ++report_times;
+                       timestamp_style = TIMESTAMP_READABLE;
+                       break;
+
+               case 't':
+                       ++report_times;
+                       timestamp_style = TIMESTAMP_PARSEABLE;
+                       break;
+
+               case 'w':
+                       write_file_name = optarg;
+                       break;
+
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+
+       if ( report_times > 1 )
+               error( "only one of -R, -r, or -t can be specified" );
+
+
+       if (optind < argc)
+               /* See if the next argument looks like a possible
+                * start time, and if so assume it is one.
+                */
+               if (isdigit(argv[optind][0]) || argv[optind][0] == '+')
+                       start_time_string = argv[optind++];
+
+       if (optind < argc)
+               if (isdigit(argv[optind][0]) || argv[optind][0] == '+')
+                       stop_time_string = argv[optind++];
+
+
+       if (optind >= argc)
+               error("at least one input file must be given");
+
+
+       first_time = first_packet_time(argv[optind]);
+       fclose( sf_readfile );
+
+
+       if (start_time_string)
+               start_time = parse_time(start_time_string, first_time);
+       else
+               start_time = first_time;
+
+       if (stop_time_string)
+               stop_time = parse_time(stop_time_string, start_time);
+
+       else
+               {
+               stop_time = start_time;
+               stop_time.tv_sec += 86400*3660; /* + 10 years; "forever" */
+               }
+
+
+       if (report_times) {
+               for (; optind < argc; ++optind)
+                       dump_times(argv[optind]);
+       }
+       
+       if (dump_flag) {
+               printf( "start\t%s\nstop\t%s\n",
+                       timestamp_to_string( &start_time ),
+                       timestamp_to_string( &stop_time ) );
+       }
+
+       if (! report_times && ! dump_flag) {
+               if ( ! strcmp( write_file_name, "-" ) &&
+                    isatty( fileno(stdout) ) )
+                       error("stdout is a terminal; redirect or use -w");
+
+               sf_write_init(write_file_name, linkinfo, thiszone, snaplen,
+                       precision);
+
+               for (; optind < argc; ++optind)
+                       extract_slice(argv[optind], &start_time, &stop_time);
+
+               fclose( sf_writefile );
+       }
+
+       return 0;
+}
+
+
+/* Returns non-zero if a string matches the format for a timestamp,
+ * 0 otherwise.
+ */
+int is_timestamp( str )
+char *str;
+       {
+       while ( isdigit(*str) || *str == '.' )
+               ++str;
+
+       return *str == '\0';
+       }
+
+
+/* Return the correction in seconds for the local time zone with respect
+ * to Greenwich time.
+ */
+long local_time_zone(timestamp)
+long timestamp;
+{
+       struct timeval now;
+       struct timezone tz;
+       long localzone;
+
+       if (gettimeofday(&now, &tz) < 0) {
+               perror("tcpslice: gettimeofday");
+               exit(1);
+       }
+       localzone = tz.tz_minuteswest * -60;
+
+       if (localtime((time_t *) &timestamp)->tm_isdst)
+               localzone += 3600;
+
+       return localzone;
+}
+
+/* Given a string specifying a time (or a time offset) and a "base time"
+ * from which to compute offsets and fill in defaults, returns a timeval
+ * containing the specified time.
+ */
+
+struct timeval
+parse_time(time_string, base_time)
+       char *time_string;
+       struct timeval base_time;
+{
+       struct tm *bt = localtime((time_t *) &base_time.tv_sec);
+       struct tm t;
+       struct timeval result;
+       time_t usecs = 0;
+       int is_delta = (time_string[0] == '+');
+
+       if ( is_delta )
+               ++time_string;  /* skip over '+' sign */
+
+       if ( is_timestamp( time_string ) )
+               { /* interpret as a raw timestamp or timestamp offset */
+               char *time_ptr;
+
+               result.tv_sec = atoi( time_string );
+               time_ptr = strchr( time_string, '.' );
+
+               if ( time_ptr )
+                       { /* microseconds are specified, too */
+                       int num_digits = strlen( time_ptr + 1 );
+                       result.tv_usec = atoi( time_ptr + 1 );
+
+                       /* turn 123.456 into 123 seconds plus 456000 usec */
+                       while ( num_digits++ < 6 )
+                               result.tv_usec *= 10;
+                       }
+
+               else
+                       result.tv_usec = 0;
+
+               if ( is_delta )
+                       {
+                       result.tv_sec += base_time.tv_sec;
+                       result.tv_usec += base_time.tv_usec;
+
+                       if ( result.tv_usec > 1000000 )
+                               {
+                               result.tv_usec -= 1000000;
+                               ++result.tv_sec;
+                               }
+                       }
+
+               return result;
+               }
+
+       if (is_delta) {
+               t = *bt;
+               usecs = base_time.tv_usec;
+       } else {
+               /* Zero struct (easy way around lack of tm_gmtoff/tm_zone
+                * under older systems) */
+               bzero((char *)&t, sizeof(t));
+
+               /* Set values to "not set" flag so we can later identify
+                * and default them.
+                */
+               t.tm_sec = t.tm_min = t.tm_hour = t.tm_mday = t.tm_mon =
+                       t.tm_year = -1;
+       }
+
+       fill_tm(time_string, is_delta, &t, &usecs);
+
+       /* Now until we reach a field that was specified, fill in the
+        * missing fields from the base time.
+        */
+#define CHECK_FIELD(field_name)                \
+       if (t.field_name < 0)                   \
+               t.field_name = bt->field_name;  \
+       else                                    \
+               break
+
+       do {    /* bogus do-while loop so "break" in CHECK_FIELD will work */
+               CHECK_FIELD(tm_year);
+               CHECK_FIELD(tm_mon);
+               CHECK_FIELD(tm_mday);
+               CHECK_FIELD(tm_hour);
+               CHECK_FIELD(tm_min);
+               CHECK_FIELD(tm_sec);
+       } while ( 0 );
+
+       /* Set remaining unspecified fields to 0. */
+#define ZERO_FIELD_IF_NOT_SET(field_name,zero_val)     \
+       if (t.field_name < 0)                           \
+               t.field_name = zero_val
+
+       if (! is_delta) {
+               ZERO_FIELD_IF_NOT_SET(tm_year,90);  /* should never happen */
+               ZERO_FIELD_IF_NOT_SET(tm_mon,0);
+               ZERO_FIELD_IF_NOT_SET(tm_mday,1);
+               ZERO_FIELD_IF_NOT_SET(tm_hour,0);
+               ZERO_FIELD_IF_NOT_SET(tm_min,0);
+               ZERO_FIELD_IF_NOT_SET(tm_sec,0);
+       }
+
+       result.tv_sec = gwtm2secs(&t);
+       result.tv_sec -= local_time_zone(result.tv_sec);
+       result.tv_usec = usecs;
+
+       return result;
+}
+
+
+/* Fill in (or add to, if is_delta is true) the time values in the
+ * tm struct "t" as specified by the time specified in the string
+ * "time_string".  "usecs_addr" is updated with the specified number
+ * of microseconds, if any.
+ */
+void
+fill_tm(time_string, is_delta, t, usecs_addr)
+       char *time_string;
+       int is_delta;   /* if true, add times in instead of replacing */
+       struct tm *t;   /* tm struct to be filled from time_string */
+       time_t *usecs_addr;
+{
+       char *t_start, *t_stop, format_ch;
+       int val;
+
+#define SET_VAL(lhs,rhs)       \
+       if (is_delta)           \
+               lhs += rhs;     \
+       else                    \
+               lhs = rhs
+
+       /* Loop through the time string parsing one specification at
+        * a time.  Each specification has the form <number><letter>
+        * where <number> indicates the amount of time and <letter>
+        * the units.
+        */
+       for (t_stop = t_start = time_string; *t_start; t_start = ++t_stop) {
+               if (! isdigit(*t_start))
+                       error("bad date format %s, problem starting at %s",
+                             time_string, t_start);
+
+               while (isdigit(*t_stop))
+                       ++t_stop;
+               if (! t_stop)
+                       error("bad date format %s, problem starting at %s",
+                             time_string, t_start);
+
+               val = atoi(t_start);
+
+               format_ch = *t_stop;
+               if ( isupper( format_ch ) )
+                       format_ch = tolower( format_ch );
+
+               switch (format_ch) {
+                       case 'y':
+                               if ( val > 1900 )
+                                       val -= 1900;
+                               SET_VAL(t->tm_year, val);
+                               break;
+
+                       case 'm':
+                               if (strchr(t_stop+1, 'D') ||
+                                   strchr(t_stop+1, 'd'))
+                                       /* it's months */
+                                       SET_VAL(t->tm_mon, val - 1);
+                               else    /* it's minutes */
+                                       SET_VAL(t->tm_min, val);
+                               break;
+
+                       case 'd':
+                               SET_VAL(t->tm_mday, val);
+                               break;
+
+                       case 'h':
+                               SET_VAL(t->tm_hour, val);
+                               break;
+
+                       case 's':
+                               SET_VAL(t->tm_sec, val);
+                               break;
+
+                       case 'u':
+                               SET_VAL(*usecs_addr, val);
+                               break;
+
+                       default:
+                               error(
+                               "bad date format %s, problem starting at %s",
+                                     time_string, t_start);
+               }
+       }
+}
+
+
+/* Return in first_time and last_time the timestamps of the first and
+ * last packets in the given file.
+ */
+void
+get_file_range( filename, first_time, last_time )
+       char filename[];
+       struct timeval *first_time;
+       struct timeval *last_time;
+{
+       *first_time = first_packet_time( filename );
+
+       if ( ! sf_find_end( first_time, last_time ) )
+               error( "couldn't find final packet in file %s", filename );
+}
+
+
+/* Returns the timestamp of the first packet in the given tcpdump save
+ * file, which as a side-effect is initialized for further save-file
+ * reading.
+ */
+
+struct timeval
+first_packet_time(filename)
+       char filename[];
+{
+       struct packet_header hdr;
+       u_char *buf;
+
+       if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision))
+               error( "bad tcpdump file %s", filename );
+
+       buf = (u_char *)malloc((unsigned)snaplen);
+
+       if (sf_next_packet(&hdr, buf, snaplen))
+               error( "bad status reading first packet in %s", filename );
+
+       free((char *)buf);
+
+       return hdr.ts;
+}
+
+
+/* Extract from the given file all packets with timestamps between
+ * the two time values given (inclusive).  These packets are written
+ * to the save file output set up by a previous call to sf_write_init().
+ * Upon return, start_time is adjusted to reflect a time just after
+ * that of the last packet written to the output.
+ */
+
+void
+extract_slice(filename, start_time, stop_time)
+       char filename[];
+       struct timeval *start_time;
+       struct timeval *stop_time;
+{
+       long start_pos, stop_pos;
+       struct timeval file_start_time, file_stop_time;
+       int status;
+       struct packet_header hdr;
+       u_char *buf;
+
+
+       if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision))
+               error( "bad tcpdump file %s", filename );
+
+       buf = (u_char *)malloc((unsigned)snaplen);
+
+       start_pos = ftell( sf_readfile );
+
+
+       if ( (status = sf_next_packet( &hdr, buf, snaplen )) )
+               error( "bad status %d reading packet in %s",
+                       status, filename );
+
+       file_start_time = hdr.ts;
+
+
+       if ( ! sf_find_end( &file_start_time, &file_stop_time ) )
+               error( "problems finding end packet of file %s",
+                       filename );
+
+       stop_pos = ftell( sf_readfile );
+
+
+       /* sf_find_packet() requires that the time it's passed as its last
+        * argument be in the range [min_time, max_time], so we enforce
+        * that constraint here.
+        */
+       if ( sf_timestamp_less_than( start_time, &file_start_time ) )
+               *start_time = file_start_time;
+
+       if ( sf_timestamp_less_than( &file_stop_time, start_time ) )
+               return; /* there aren't any packets of interest in the file */
+
+
+       sf_find_packet( &file_start_time, start_pos,
+                       &file_stop_time, stop_pos,
+                       start_time );
+
+       for ( ; ; )
+               {
+               struct timeval *timestamp;
+               status = sf_next_packet( &hdr, buf, snaplen );
+
+               if ( status )
+                       {
+                       if ( status != SFERR_EOF )
+                               error( "bad status %d reading packet in %s",
+                                       status, filename );
+                       break;
+                       }
+
+               timestamp = &hdr.ts;
+
+               if ( ! sf_timestamp_less_than( timestamp, start_time ) )
+                       { /* packet is recent enough */
+                       if ( sf_timestamp_less_than( stop_time, timestamp ) )
+                               /* We've gone beyond the end of the region
+                                * of interest ... We're done with this file.
+                                */
+                               break;
+
+                       sf_write( buf, timestamp, (int) hdr.len,
+                                 (int) hdr.caplen );
+                       *start_time = *timestamp;
+
+                       /* We know that each packet is guaranteed to have
+                        * a unique timestamp, so we push forward the
+                        * allowed minimum time to weed out duplicate
+                        * packets.
+                        */
+                       ++start_time->tv_usec;
+                       }
+               }
+
+       fclose( sf_readfile );
+       free( (char *) buf );
+}
+
+
+/* Translates a timestamp to the time format specified by the user.
+ * Returns a pointer to the translation residing in a static buffer.
+ * There are two such buffers, which are alternated on subseqeuent
+ * calls, so two calls may be made to this routine without worrying
+ * about the results of the first call being overwritten by the
+ * results of the second.
+ */
+
+char *
+timestamp_to_string(timestamp)
+       struct timeval *timestamp;
+{
+       struct tm *t;
+#define NUM_BUFFERS 2
+       static char buffers[NUM_BUFFERS][128];
+       static int buffer_to_use = 0;
+       char *buf;
+
+       buf = buffers[buffer_to_use];
+       buffer_to_use = (buffer_to_use + 1) % NUM_BUFFERS;
+
+       switch ( timestamp_style )
+           {
+           case TIMESTAMP_RAW:
+               sprintf( buf, "%d.%d", timestamp->tv_sec, timestamp->tv_usec );
+               break;
+
+           case TIMESTAMP_READABLE:
+               t = localtime((time_t *) &timestamp->tv_sec);
+               strcpy( buf, asctime( t ) );
+               buf[24] = '\0'; /* nuke final newline */
+               break;
+
+           case TIMESTAMP_PARSEABLE:
+               t = localtime((time_t *) &timestamp->tv_sec);
+               sprintf( buf, "%02dy%02dm%02dd%02dh%02dm%02ds%06du",
+                       t->tm_year, t->tm_mon + 1, t->tm_mday, t->tm_hour,
+                       t->tm_min, t->tm_sec, timestamp->tv_usec );
+               break;
+
+           }
+
+       return buf;
+}
+
+
+/* Given a tcpdump save filename, reports on the times of the first
+ * and last packets in the file.
+ */
+
+void
+dump_times(filename)
+       char filename[];
+{
+       struct timeval first_time, last_time;
+
+       get_file_range( filename, &first_time, &last_time );
+
+       printf( "%s\t%s\t%s\n",
+               filename,
+               timestamp_to_string( &first_time ),
+               timestamp_to_string( &last_time ) );
+}
+
+void
+usage()
+{
+       (void)fprintf(stderr, "tcpslice for tcpdump version %d.%d\n",
+                     VERSION_MAJOR, VERSION_MINOR);
+       (void)fprintf(stderr,
+"Usage: tcpslice [-dRrt] [-w file] [start-time [end-time]] file ... \n");
+
+       exit(-1);
+}