]> err.no Git - dpkg/commitdiff
dpkg (1.1.4); priority=MEDIUM
authorIan Jackson <ian@chiark.chu.cam.ac.uk>
Thu, 4 Apr 1996 00:58:40 +0000 (01:58 +0100)
committerIan Jackson <ian@chiark.chu.cam.ac.uk>
Thu, 4 Apr 1996 00:58:40 +0000 (01:58 +0100)
  * Allow overwriting of conflicting packages being removed.  (Bug#2614.)

  * a.out control file says Pre-Depends: libc4 | libc.  (Bug#2640.)
  * ELF control file and libc dependencies changed to use finalised scheme.
  * ELF control file and libc dependencies for i386 only.  (Bug#2617.)

  * Guidelines say use only released libraries and compilers.
  * Install wishlist as /usr/doc/dpkg/WISHLIST.
  * Remove spurious entries for Guidelines in info dir file.

  * dpkg-deb --build checks permissions on control (DEBIAN) directory.

  * Spaces in control file fields not copied by dpkg-split.  (Bug#2633.)
  * Spaces in split file part control data ignore.  (Bug#2633.)

  * Portability fixes, including patch from Richard Kettlewell.
  * Fixed minor configure.in bug causing mangled GCC -W options.

 -- Ian Jackson <ian@chiark.chu.cam.ac.uk>  Thu, 4 Apr 1996 01:58:40 +0100

189 files changed:
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
archtable [new file with mode: 0644]
config.h.bot [new file with mode: 0644]
config.h.in [new file with mode: 0644]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
debian.Changelog [new file with mode: 0644]
debian.README [new file with mode: 0644]
debian.control [new file with mode: 0644]
debian.controlaout [new file with mode: 0644]
debian.postinst [new file with mode: 0755]
debian.preinst [new file with mode: 0755]
debian.prerm [new file with mode: 0644]
debian.rules [new file with mode: 0755]
doc/Makefile.in [new file with mode: 0644]
doc/auto-deconfiguration.txt [new file with mode: 0644]
doc/database-structure.fig [new file with mode: 0644]
doc/deb-control.5 [new file with mode: 0644]
doc/deb.5 [new file with mode: 0644]
doc/dependency-ordering.txt [new file with mode: 0644]
doc/descriptions.txt [new file with mode: 0644]
doc/disappear-replace.txt [new file with mode: 0644]
doc/diversions.text [new file with mode: 0644]
doc/dpkg.texi [new file with mode: 0644]
doc/essential-flag.txt [new file with mode: 0644]
doc/guidelines.info-1 [new file with mode: 0644]
doc/guidelines.info-2 [new file with mode: 0644]
doc/guidelines.texi [new file with mode: 0644]
doc/guidelines.texi.beforeeric [new file with mode: 0644]
doc/guidelines.texi.rej [new file with mode: 0644]
doc/junk [new file with mode: 0644]
doc/maintainer-script-args.txt [new file with mode: 0644]
doc/upgrades+errors.txt [new file with mode: 0644]
doc/version-ordering.txt [new file with mode: 0644]
doc/virtual-dependencies.txt [new file with mode: 0644]
dpkg-deb/Makefile.in [new file with mode: 0644]
dpkg-deb/build.c [new file with mode: 0644]
dpkg-deb/debugmake [new file with mode: 0755]
dpkg-deb/dpkg-deb.8 [new file with mode: 0644]
dpkg-deb/dpkg-deb.8-vuori [new file with mode: 0644]
dpkg-deb/dpkg-deb.h [new file with mode: 0644]
dpkg-deb/extract.c [new file with mode: 0644]
dpkg-deb/info.c [new file with mode: 0644]
dpkg-deb/main.c [new file with mode: 0644]
dpkg-deb/mkdeb.sh [new file with mode: 0644]
dselect/Makefile.in [new file with mode: 0644]
dselect/basecmds.cc [new file with mode: 0644]
dselect/baselist.cc [new file with mode: 0644]
dselect/basetop.cc [new file with mode: 0644]
dselect/bindings.cc [new file with mode: 0644]
dselect/bindings.h [new file with mode: 0644]
dselect/checkunimp.pl [new file with mode: 0755]
dselect/curkeys.cc [new file with mode: 0644]
dselect/debugmake [new file with mode: 0755]
dselect/dselect.8 [new file with mode: 0644]
dselect/dselect.h [new file with mode: 0644]
dselect/helpmsgs.src [new file with mode: 0644]
dselect/junk [new file with mode: 0644]
dselect/keyoverride [new file with mode: 0644]
dselect/keys.c [new file with mode: 0644]
dselect/kt.c [new file with mode: 0644]
dselect/kt.cc [new file with mode: 0644]
dselect/main.cc [new file with mode: 0644]
dselect/methkeys.cc [new file with mode: 0644]
dselect/methlist.cc [new file with mode: 0644]
dselect/method.cc [new file with mode: 0644]
dselect/method.h [new file with mode: 0644]
dselect/methparse.cc [new file with mode: 0644]
dselect/mkcurkeys.pl [new file with mode: 0755]
dselect/mkhelpmsgs.pl [new file with mode: 0755]
dselect/pkgcmds.cc [new file with mode: 0644]
dselect/pkgdepcon.cc [new file with mode: 0644]
dselect/pkgdisplay.cc [new file with mode: 0644]
dselect/pkginfo.cc [new file with mode: 0644]
dselect/pkgkeys.cc [new file with mode: 0644]
dselect/pkglist.cc [new file with mode: 0644]
dselect/pkglist.h [new file with mode: 0644]
dselect/pkgsublist.cc [new file with mode: 0644]
dselect/pkgtop.cc [new file with mode: 0644]
dselect/rp [new file with mode: 0755]
dselect/t.c [new file with mode: 0644]
include/Makefile.in [new file with mode: 0644]
include/dpkg-db.h [new file with mode: 0644]
include/dpkg.h [new file with mode: 0644]
include/myopt.h [new file with mode: 0644]
include/tarfn.h [new file with mode: 0644]
insert-version.pl [new file with mode: 0755]
install.sh [new file with mode: 0755]
lib/Makefile.in [new file with mode: 0644]
lib/compat.c [new file with mode: 0644]
lib/database.c [new file with mode: 0644]
lib/dbmodify.c [new file with mode: 0644]
lib/debugmake [new file with mode: 0755]
lib/dump.c [new file with mode: 0644]
lib/ehandle.c [new file with mode: 0644]
lib/fields.c [new file with mode: 0644]
lib/lock.c [new file with mode: 0644]
lib/mlib.c [new file with mode: 0644]
lib/myopt.c [new file with mode: 0644]
lib/nfmalloc.c [new file with mode: 0644]
lib/parse.c [new file with mode: 0644]
lib/parsedump.h [new file with mode: 0644]
lib/parsehelp.c [new file with mode: 0644]
lib/showcright.c [new file with mode: 0644]
lib/star.c [new file with mode: 0644]
lib/tarfn.c [new file with mode: 0644]
lib/varbuf.c [new file with mode: 0644]
lib/vercmp.c [new file with mode: 0644]
main/Makefile.in [new file with mode: 0644]
main/archives.c [new file with mode: 0644]
main/archives.h [new file with mode: 0644]
main/archtable.inc [new file with mode: 0644]
main/cleanup.c [new file with mode: 0644]
main/configure.c [new file with mode: 0644]
main/debugmake [new file with mode: 0755]
main/depcon.c [new file with mode: 0644]
main/dpkg.8 [new file with mode: 0644]
main/dpkg.8-vuori [new file with mode: 0644]
main/enquiry.c [new file with mode: 0644]
main/errors.c [new file with mode: 0644]
main/filesdb.c [new file with mode: 0644]
main/filesdb.h [new file with mode: 0644]
main/help.c [new file with mode: 0644]
main/junk [new file with mode: 0644]
main/main.c [new file with mode: 0644]
main/main.h [new file with mode: 0644]
main/packages.c [new file with mode: 0644]
main/processarc.c [new file with mode: 0644]
main/remove.c [new file with mode: 0644]
main/update.c [new file with mode: 0644]
md5sum/Makefile.in [new file with mode: 0644]
md5sum/md5.c [new file with mode: 0644]
md5sum/md5.h [new file with mode: 0644]
md5sum/md5sum.1 [new file with mode: 0644]
md5sum/md5sum.c [new file with mode: 0644]
methods/Makefile.in [new file with mode: 0644]
methods/disk.desc.cdrom [new file with mode: 0644]
methods/disk.desc.harddisk [new file with mode: 0644]
methods/disk.desc.mounted [new file with mode: 0644]
methods/disk.desc.nfs [new file with mode: 0644]
methods/disk.install [new file with mode: 0644]
methods/disk.names [new file with mode: 0644]
methods/disk.setup [new file with mode: 0644]
methods/disk.update [new file with mode: 0644]
methods/floppy.desc.floppy [new file with mode: 0644]
methods/floppy.install [new file with mode: 0644]
methods/floppy.names [new file with mode: 0644]
methods/floppy.setup [new file with mode: 0644]
methods/floppy.update [new file with mode: 0644]
methods/hd.setup [new file with mode: 0755]
methods/hd.unpack [new file with mode: 0755]
methods/hd.update [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
scripts/Makefile.in [new file with mode: 0644]
scripts/dpkg-divert.pl [new file with mode: 0644]
scripts/dpkg-name.1 [new file with mode: 0644]
scripts/dpkg-name.sh [new file with mode: 0755]
scripts/dpkg-scanpackages.pl [new file with mode: 0755]
scripts/install-info.8 [new file with mode: 0644]
scripts/install-info.pl [new file with mode: 0755]
scripts/lib.pl [new file with mode: 0644]
scripts/perl-dpkg.pl [new file with mode: 0755]
scripts/start-stop-daemon.8 [new file with mode: 0644]
scripts/start-stop-daemon.pl [new file with mode: 0755]
scripts/update-alternatives.8 [new file with mode: 0644]
scripts/update-alternatives.pl [new file with mode: 0755]
scripts/update-rc.d.8 [new file with mode: 0644]
scripts/update-rc.d.sh [new file with mode: 0755]
split/Makefile.in [new file with mode: 0644]
split/debugmake [new file with mode: 0755]
split/dpkg-split.8 [new file with mode: 0644]
split/dpkg-split.h [new file with mode: 0644]
split/info.c [new file with mode: 0644]
split/join.c [new file with mode: 0644]
split/junk [new file with mode: 0644]
split/magic [new file with mode: 0644]
split/main.c [new file with mode: 0644]
split/mksplit [new file with mode: 0755]
split/mksplit.pl [new file with mode: 0644]
split/old-mksplit.sh [new file with mode: 0644]
split/queue.c [new file with mode: 0644]
split/split.c [new file with mode: 0644]
version.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..e77696a
--- /dev/null
+++ b/COPYING
@@ -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
+           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/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..8a7d026
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,146 @@
+   This is a generic INSTALL file for utilities distributions.
+If this package does not come with, e.g., installable documentation or
+data files, please ignore the references to them below.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and
+creates the Makefile(s) (one in each subdirectory of the source
+directory).  In some packages it creates a C header file containing
+system-dependent definitions.  It also creates a file `config.status'
+that you can run in the future to recreate the current configuration.
+
+To compile this package:
+
+1.  Configure the package for your system.
+
+   Normally, you just `cd' to the directory containing the package's
+source code and type `./configure'.  If you're using `csh' on an old
+version of System V, you might need to type `sh configure' instead to
+prevent `csh' from trying to execute `configure' itself.
+
+   Running `configure' takes awhile.  While it is running, it
+prints some messages that tell what it is doing.  If you don't want to
+see any messages, run `configure' with its standard output redirected
+to `/dev/null'; for example, `./configure >/dev/null'.
+
+   To compile the package in a different directory from the one
+containing the source code, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  If
+for some reason `configure' is not in the source code directory that
+you are configuring, then it will report that it can't find the source
+code.  In that case, run `configure' with the option `--srcdir=DIR',
+where DIR is the directory that contains the source code.
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.  Alternately, you can do so by consistently
+giving a value for the `prefix' variable when you run `make', e.g.,
+     make prefix=/usr/gnu
+     make prefix=/usr/gnu install
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH' or set the `make'
+variable `exec_prefix' to PATH, the package will use PATH as the prefix
+for installing programs and libraries.  Data files and documentation
+will still use the regular prefix.  Normally, all files are installed
+using the same prefix.
+
+   Some packages pay attention to `--with-PACKAGE' options to
+`configure', where PACKAGE is something like `gnu-as' or `x' (for the
+X Window System).  They may also pay attention to `--enable-FEATURE'
+options, where FEATURE indicates an optional part of the package.  The
+README should mention any `--with-' and `--enable-' options that the
+package recognizes.
+
+   `configure' also recognizes the following options:
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+     Do not print messages saying which checks are being made.
+
+`--verbose'
+     Print the results of the checks.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--x-includes=DIR'
+     X include files are in DIR.
+
+`--x-libraries=DIR'
+     X library files are in DIR.
+
+   `configure' also accepts and ignores some other options.
+
+   On systems that require unusual options for compilation or linking
+that the package's `configure' script does not know about, you can give
+`configure' initial values for variables by setting them in the
+environment.  In Bourne-compatible shells, you can do that on the
+command line like this:
+
+     CC='gcc -traditional' LIBS=-lposix ./configure
+
+On systems that have the `env' program, you can do it like this:
+
+     env CC='gcc -traditional' LIBS=-lposix ./configure
+
+   Here are the `make' variables that you might want to override with
+environment variables when running `configure'.
+
+   For these variables, any value given in the environment overrides the
+value that `configure' would choose:
+
+ - Variable: CC
+     C compiler program.  The default is `cc'.
+
+ - Variable: INSTALL
+     Program to use to install files.  The default is `install' if you
+     have it, `cp' otherwise.
+
+   For these variables, any value given in the environment is added to
+the value that `configure' chooses:
+
+ - Variable: DEFS
+     Configuration options, in the form `-Dfoo -Dbar...'.  Do not use
+     this variable in packages that create a configuration header file.
+
+ - Variable: LIBS
+     Libraries to link with, in the form `-lfoo -lbar...'.
+
+   If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+2.  Type `make' to compile the package.  If you want, you can override
+the `make' variables CFLAGS and LDFLAGS like this:
+
+       make CFLAGS=-O2 LDFLAGS=-s
+
+3.  If the package comes with self-tests and you want to run them,
+type `make check'.  If you're not sure whether there are any, try it;
+if `make' responds with something like
+       make: *** No way to make target `check'.  Stop.
+then the package does not come with self-tests.
+
+4.  Type `make install' to install programs, data files, and
+documentation.
+
+5.  You can remove the program binaries and object files from the
+source directory by typing `make clean'.  To also remove the
+Makefile(s), the header file containing system-dependent definitions
+(if the package uses one), and `config.status' (all the files that
+`configure' created), type `make distclean'.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need it if you want to regenerate
+`configure' using a newer version of `autoconf'.
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..40f01b6
--- /dev/null
@@ -0,0 +1,131 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+docdir = $(prefix)/doc
+devdocdir = $(docdir)/dpkg
+copyingfile = $(docdir)/copyright/dpkg
+infodir = $(prefix)/info
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libdir = $(prefix)/lib
+dpkglibdir = $(libdir)/dpkg
+methodsdir = $(dpkglibdir)/methods
+datadir = /var/lib/dpkg
+methodsdatadir = $(datadir)/methods
+methodsmnt = $(datadir)/methods/mnt
+pinfodir = $(datadir)/info
+pupdatesdir = $(datadir)/updates
+altsdatadir = $(datadir)/alternatives
+partsdir = $(datadir)/parts
+mandir = $(prefix)/man
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+man1 = 1
+man5 = 5
+man8 = 8
+etcdir= /etc
+altsetcdir = $(etcdir)/alternatives
+
+BOURNESHELL = /bin/sh
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+
+SUBDIRS = lib main dpkg-deb split md5sum scripts doc include dselect methods
+PORTABLEDIRS = lib dpkg-deb split md5sum
+
+.SUFFIXES:     .c .o
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+all:           version
+               set -e; for d in $(SUBDIRS) ; do \
+                       cd $$d ; \
+                       $(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)'; \
+                       cd .. ; \
+               done
+
+install:       all
+               $(BOURNESHELL) $(srcdir)/mkinstalldirs $(bindir) $(sbindir) \
+                       $(man1dir) $(man5dir) $(man8dir) $(devdocdir) \
+                       $(libdir) $(datadir) $(pinfodir) $(pupdatesdir) \
+                       $(dpkglibdir) $(methodsdir) $(methodsdatadir) $(methodsmnt) \
+                       $(altsdatadir) $(altsetcdir) $(partsdir) $(infodir)
+               set -e; for d in $(SUBDIRS) ; do \
+                       cd $$d ; \
+                       $(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' \
+                               install ; \
+                       cd .. ; \
+               done
+               $(INSTALL_DATA) COPYING $(copyingfile)
+
+portable:      version
+               set -e; for d in lib dpkg-deb split md5sum ; do \
+                       cd $$d ; \
+                       $(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' ; \
+                       cd .. ; \
+               done
+
+install-portable: portable
+               $(BOURNESHELL) $(srcdir)/mkinstalldirs $(bindir) \
+                       $(man1dir) $(man8dir) $(libdir) $(dpkglibdir)
+               set -e; for d in $(PORTABLEDIRS) ; do \
+                       cd $$d ; \
+                       $(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' \
+                               install ; \
+                       cd .. ; \
+               done
+#              $(INSTALL_DATA) COPYING $(copyingfile)
+
+autoconf:
+               autoheader
+               autoconf
+
+clean:
+               set -e; for d in $(SUBDIRS) ; do \
+                       cd $$d ; \
+                       $(MAKE) clean ; \
+                       cd .. ; \
+               done
+               rm -f core version.h.new
+
+distclean:     clean
+               set -e; for d in $(SUBDIRS) ; do \
+                       cd $$d ; \
+                       $(MAKE) distclean ; \
+                       cd .. ; \
+               done
+               rm -f Makefile *.orig *~ *.~* ./#*#
+               rm -f config.h config.status install config.cache config.log
+
+version:
+               perl insert-version.pl <version.h >version.h.new
+               cmp -s version.h.new version.h || mv version.h.new version.h
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..865bad7
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,72 @@
+(-*- indented-text -*-)
+\f
+
+CHANGES SINCE dpkg 0.93.7:
+
+ * a Perl-based front-end with many new features has replaced dpkg.sh.
+   The new features are detailed below.  dpkg.pl is not finished,
+   however, as it does not yet support CONFLICTS, DEPENDS, OPTIONAL,
+   or RECOMMENDED.  All of the above will be supported in Debian 0.93.
+
+   In addition, it does not yet support PARTS, but that may wait until
+   Debian 0.94.  (In the meantime, we can create disk-sized packages by
+   hand.)
+
+   dpkg.pl has been constructed from code originally by Matt Welsh,
+   with additions by Carl Streeter, Ian Murdock, and Ian Jackson.
+
+New features in dpkg.pl:
+
+ * dpkg.pl can now manipulate many packages at a time; dpkg.sh could
+   only manipulate one package at a time.
+
+ * dpkg.pl supports pre-installation, post-installation, pre-removal,
+   and post-removal scripts.  During batch installation,
+   post-installation scripts are executed after all packages have
+   been installed.  (dpkg.sh supported all of the above except the
+   batch installation feature, because dpkg.sh did not itself support
+   batch installation.)
+
+ * dpkg.pl now supports the upgrading of packages.  A newer version of
+   a package, when released, can be obtained and installed normally on
+   the system to replace an older, previously installed version of it,
+   all with a minimum of manuals steps.
+
+   During the installation process, dpkg.pl determines whether or not
+   a version of the package is currently installed on the system.  If
+   it is, it determines whether it is an older version than the
+   package being installed (in which case we are ``upgrading'', and
+   the installation proceeds after saving the configuration files and
+   removing the older version), or whether it is the same or a newer
+   version than the package being installed (in which case we are, for
+   whatever reason, attempting to install a package twice or
+   ``downgrading'', and dpkg.pl asks for confirmation).
+
+ * dpkg.pl now supports automatic and intelligent configuration file
+   updates during the upgrade process.  During a package upgrade, it
+   determines when a configuration file has changed since the last
+   installation and, for those that have, prompts the user whether to
+   keep the older or newer configuration file, providing them with
+   default responses.
+
+New features in dpkg-deb:
+
+ * dpkg-util.deb has been renamed to dpkg-deb, for brevity.
+
+ * dpkg-deb is much less verbose, and in most cases it says nothing
+   unless an error has occurred.  The front-end is expected to provide
+   the necessary verbosity when appropriate.
+
+ * `dpkg-deb --describe' now outputs the description only, without the
+   ``Description:'' label.
+
+ * `dpkg-deb --list' output is now sorted by package name.
+
+ * `dpkg-deb --remove' bug fix: in dpkg 0.93.7 (or earlier), some
+   directories did not get properly removed.  This has been fixed.
+
+ * `dpkg-deb --version' now outputs the version information only,
+   without the `Version:'' label, and without maintainer information.
+
+ * `dpkg-deb --version' now provides the version of dpkg if no
+   argument is specified.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..5fd12aa
--- /dev/null
+++ b/README
@@ -0,0 +1,23 @@
+-*- text -*-
+
+Please see the file `Guidelines' for the guidelines for creating and
+maintaining Debian packages.  dpkg Texinfo documentation and a manual
+page will be available with the next release, but in the interest of
+time I am releasing dpkg 0.93.8 without them.
+
+Please send bug reports and comments to <debian-bugs@pixar.com>.
+Please be sure to put the following at the top of the message body:
+
+Package: dpkg
+
+This will enter your bug report in our tracking system, and will help
+us to investigate and respond to your problem as promptly as possible.
+
+Please read the file `COPYING' for copying conditions.
+
+Please read the file `INSTALL' for installation instructions.
+
+Please read the file `NEWS' for a description of new features, etc.
+
+[ Note for users of GCC 2.7.0: you must compile at least
+ `dselect/main.cc' with only -O2, due to a bug in GCC. ]
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..3341868
--- /dev/null
+++ b/TODO
@@ -0,0 +1,57 @@
+Here are some currently-known inadequacies:
+
+urgent
+ * Pre-Depends installation ordering
+
+done
+ * a.out version
+ * uncomment ELF preinst modification
+ * Replaces (auto-deselect for conflicts)
+ * Replaces (don't overwrite otherwise)
+ * compile with ELF GCC out of the box
+ * dpkg --print-architecture
+ * Architecture field check
+ * symlink rename change
+
+bugs that need to be fixed quickly
+ * version numbers not starting digit early.
+ * check description in dpkg-deb
+ * field overflow in dpkg --list
+ * _always_ show section in --yet-to-unpack
+ * automatically do --yet-to-unpack in installation methods
+ * check depending packages when installing new version.
+ * error handling from some dselect actions. 1399
+ * Several things ought to be configurable but aren't.
+ * Filenames containing newlines.  Conffile names containing spaces.
+ * dpkg --status for virtual packages
+ * dselect bottom window too large, and/or resize
+ * update-alternatives prompting.
+ * logging, both transcript logs (kept briefly)
+   and action logs (kept forever?)  957
+ * start-stop-daemon process status check. 1480
+ * remove old docs from /usr/doc/dpkg.
+
+other stuff unlikely to get done soon
+ * single maintainer script, and new package getting there first
+ * dpkg -s show something for virtual packages
+ * dpkg --listfiles should do better for multi-package files  (pkg, pkg: ...)
+ * settable defaults for update-rc.d
+ * local conffiles
+ * hooks
+ * gzip -0 option for dpkg-deb
+ * There is no documentation. 1526
+ * newbie interface to dselect. 1037
+ * FTP installation method
+ * `template' file giving default selections of dselect.
+ * update-rc.d in C
+ * start-stop-daemon in C. 1670
+ * dselect per-half focus and keybindings improvements. 1555
+ * floppy map (where are the files)
+ * highlight or pre-sort or something new or changed packages,
+   during upgrade selection.
+ * how to change case of package names
+ * support for adding files to dpkg's file lists
+ * side-by-side version display
+ * `fake' or `null' packages
+ * --purge remove empty directories which used too contain conffiles
+ * conffiles handling options, including `replace removed files'
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..0dae8ac
--- /dev/null
@@ -0,0 +1,31 @@
+/* Additional tests: */
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_INLINE
+
+/* Define if sysinfo is available.  */
+#undef HAVE_SYSINFO
+
+/* Define if __NR_sysinfo is available.  */
+#undef HAVE_NRSYSINFO
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_ALPHASORT_DECLARATION
+
+/* Define if function attributes a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_ATTRIB
+
+/* Define if constant functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_CONST
+
+/* Define if nonreturning functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_NORETURN
+
+/* Define if printf-format argument lists a la GCC are available.  */
+#undef HAVE_GNUC25_PRINTFFORMAT
+
+/* Set this to the canonical Debian architecture string for this CPU type. */
+#undef ARCHITECTURE
+
+/* Set this to 1 to build new archives by default. */
+#define BUILDOLDPKGFORMAT 0
diff --git a/archtable b/archtable
new file mode 100644 (file)
index 0000000..97a1cad
--- /dev/null
+++ b/archtable
@@ -0,0 +1,21 @@
+# This file contains a table of known architecture strings, with
+# things to map them to. `configure' will take the output of gcc
+# --print-libgcc-file-name, strip off leading directories up to and
+# including gcc-lib, strip off trailing /libgcc.a and trailing version
+# number directory, and then strip off everything after the first
+# hyphen.  The idea is that you're left with this bit:
+#   $ gcc --print-libgcc-file-name
+#   /usr/lib/gcc-lib/i486-linux/2.7.2/libgcc.a
+#                    ^^^^
+# This is then looked up in the table below, to find out what to map
+# it to.  If it isn't found then configure will print a warning and
+# continue.  You can override configure's ideas using --with-arch.
+
+i386   i386
+i486   i386
+i586   i386
+sparc  sparc
+alpha  alpha
+m68k   m68k
+arm    arm
+ppc    ppc
diff --git a/config.h.bot b/config.h.bot
new file mode 100644 (file)
index 0000000..06751db
--- /dev/null
@@ -0,0 +1,129 @@
+
+/* These are from config.h.bot, pasted onto the end of config.h.in. */
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* Use the definitions: */
+
+/* Give us an unsigned 32-bit data type. */
+#if SIZEOF_UNSIGNED_LONG==4
+#define UWORD32 unsigned long
+#elif SIZEOF_UNSIGNED_INT==4
+#define UWORD32 unsigned int
+#else
+#error I do not know what to use for a UWORD32.
+#endif
+
+/* The maximum length of a #! interpreter displayed by dpkg-deb. */
+#ifdef PATH_MAX
+#define INTERPRETER_MAX PATH_MAX
+#else
+#define INTERPRETER_MAX 1024
+#endif
+
+/* GNU C attributes. */
+#ifndef FUNCATTR
+#ifdef HAVE_GNUC25_ATTRIB
+#define FUNCATTR(x) __attribute__(x)
+#else
+#define FUNCATTR(x)
+#endif
+#endif
+
+/* GNU C printf formats, or null. */
+#ifndef ATTRPRINTF
+#ifdef HAVE_GNUC25_PRINTFFORMAT
+#define ATTRPRINTF(si,tc) format(printf,si,tc)
+#else
+#define ATTRPRINTF(si,tc)
+#endif
+#endif
+#ifndef PRINTFFORMAT
+#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
+#endif
+
+/* GNU C nonreturning functions, or null. */
+#ifndef ATTRNORETURN
+#ifdef HAVE_GNUC25_NORETURN
+#define ATTRNORETURN noreturn
+#else
+#define ATTRNORETURN
+#endif
+#endif
+#ifndef NONRETURNING
+#define NONRETURNING FUNCATTR((ATTRNORETURN))
+#endif
+
+/* Combination of both the above. */
+#ifndef NONRETURNPRINTFFORMAT
+#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
+#endif
+
+/* GNU C constant functions, or null. */
+#ifndef ATTRCONST
+#ifdef HAVE_GNUC25_CONST
+#define ATTRCONST const
+#else
+#define ATTRCONST
+#endif
+#endif
+#ifndef CONSTANT
+#define CONSTANT FUNCATTR((ATTRCONST))
+#endif
+
+/* Declare strerror if we don't have it already. */
+#ifndef HAVE_STRERROR
+const char *strerror(int);
+#endif
+
+/* Declare strsignal if we don't have it already. */
+#ifndef HAVE_STRSIGNAL
+const char *strsignal(int);
+#endif
+
+/* Declare scandir if we don't have it already. */
+#ifndef HAVE_SCANDIR
+struct dirent;
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*));
+#endif
+
+/* Declare alphasort if we don't have it already. */
+#if !defined(HAVE_ALPHASORT) || !defined(HAVE_ALPHASORT_DECLARATION)
+struct dirent;
+int alphasort(const struct dirent *a, const struct dirent *b);
+#endif
+
+/* Declare unsetenv if we don't have it already. */
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *x);
+#endif
+
+/* Define strtoul if we don't have it already. */
+#ifndef HAVE_STRTOUL
+#define strtoul strtol
+#endif
+
+/* Sort out sysinfo */
+#if !defined(HAVE_SYSINFO) && defined(HAVE_NRSYSINFO)
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+static inline _syscall1(int,sysinfo,struct sysinfo*,info)
+#endif
+
+/* Define WCOREDUMP if we don't have it already - coredumps won't be
+ * detected, though.
+ */
+#ifndef WCOREDUMP
+#define WCOREDUMP(x) 0
+#endif
+
+/* Set BUILDOLDPKGFORMAT to 1 to build old-format archives by default.
+ */
+#ifndef BUILDOLDPKGFORMAT
+#define BUILDOLDPKGFORMAT 0
+#endif
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..ad44f3f
--- /dev/null
@@ -0,0 +1,212 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef mode_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_INLINE
+
+/* Define if sysinfo is available.  */
+#undef HAVE_SYSINFO
+
+/* Define if __NR_sysinfo is available.  */
+#undef HAVE_NRSYSINFO
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_ALPHASORT_DECLARATION
+
+/* Define if function attributes a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_ATTRIB
+
+/* Define if constant functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_CONST
+
+/* Define if nonreturning functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_NORETURN
+
+/* Define if printf-format argument lists a la GCC are available.  */
+#undef HAVE_GNUC25_PRINTFFORMAT
+
+/* Set this to the canonical Debian architecture string for this CPU type. */
+#undef ARCHITECTURE
+
+/* Set this to 1 to build new archives by default. */
+#define BUILDOLDPKGFORMAT 0
+
+/* The number of bytes in a unsigned int.  */
+#undef SIZEOF_UNSIGNED_INT
+
+/* The number of bytes in a unsigned long.  */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* Define if you have the alphasort function.  */
+#undef HAVE_ALPHASORT
+
+/* Define if you have the scandir function.  */
+#undef HAVE_SCANDIR
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strsignal function.  */
+#undef HAVE_STRSIGNAL
+
+/* Define if you have the strtoul function.  */
+#undef HAVE_STRTOUL
+
+/* Define if you have the unsetenv function.  */
+#undef HAVE_UNSETENV
+
+/* Define if you have the <sys/cdefs.h> header file.  */
+#undef HAVE_SYS_CDEFS_H
+
+/* These are from config.h.bot, pasted onto the end of config.h.in. */
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* Use the definitions: */
+
+/* Give us an unsigned 32-bit data type. */
+#if SIZEOF_UNSIGNED_LONG==4
+#define UWORD32 unsigned long
+#elif SIZEOF_UNSIGNED_INT==4
+#define UWORD32 unsigned int
+#else
+#error I do not know what to use for a UWORD32.
+#endif
+
+/* The maximum length of a #! interpreter displayed by dpkg-deb. */
+#ifdef PATH_MAX
+#define INTERPRETER_MAX PATH_MAX
+#else
+#define INTERPRETER_MAX 1024
+#endif
+
+/* GNU C attributes. */
+#ifndef FUNCATTR
+#ifdef HAVE_GNUC25_ATTRIB
+#define FUNCATTR(x) __attribute__(x)
+#else
+#define FUNCATTR(x)
+#endif
+#endif
+
+/* GNU C printf formats, or null. */
+#ifndef ATTRPRINTF
+#ifdef HAVE_GNUC25_PRINTFFORMAT
+#define ATTRPRINTF(si,tc) format(printf,si,tc)
+#else
+#define ATTRPRINTF(si,tc)
+#endif
+#endif
+#ifndef PRINTFFORMAT
+#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
+#endif
+
+/* GNU C nonreturning functions, or null. */
+#ifndef ATTRNORETURN
+#ifdef HAVE_GNUC25_NORETURN
+#define ATTRNORETURN noreturn
+#else
+#define ATTRNORETURN
+#endif
+#endif
+#ifndef NONRETURNING
+#define NONRETURNING FUNCATTR((ATTRNORETURN))
+#endif
+
+/* Combination of both the above. */
+#ifndef NONRETURNPRINTFFORMAT
+#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
+#endif
+
+/* GNU C constant functions, or null. */
+#ifndef ATTRCONST
+#ifdef HAVE_GNUC25_CONST
+#define ATTRCONST const
+#else
+#define ATTRCONST
+#endif
+#endif
+#ifndef CONSTANT
+#define CONSTANT FUNCATTR((ATTRCONST))
+#endif
+
+/* Declare strerror if we don't have it already. */
+#ifndef HAVE_STRERROR
+const char *strerror(int);
+#endif
+
+/* Declare strsignal if we don't have it already. */
+#ifndef HAVE_STRSIGNAL
+const char *strsignal(int);
+#endif
+
+/* Declare scandir if we don't have it already. */
+#ifndef HAVE_SCANDIR
+struct dirent;
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*));
+#endif
+
+/* Declare alphasort if we don't have it already. */
+#if !defined(HAVE_ALPHASORT) || !defined(HAVE_ALPHASORT_DECLARATION)
+struct dirent;
+int alphasort(const struct dirent *a, const struct dirent *b);
+#endif
+
+/* Declare unsetenv if we don't have it already. */
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *x);
+#endif
+
+/* Define strtoul if we don't have it already. */
+#ifndef HAVE_STRTOUL
+#define strtoul strtol
+#endif
+
+/* Sort out sysinfo */
+#if !defined(HAVE_SYSINFO) && defined(HAVE_NRSYSINFO)
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+static inline _syscall1(int,sysinfo,struct sysinfo*,info)
+#endif
+
+/* Define WCOREDUMP if we don't have it already - coredumps won't be
+ * detected, though.
+ */
+#ifndef WCOREDUMP
+#define WCOREDUMP(x) 0
+#endif
+
+/* Set BUILDOLDPKGFORMAT to 1 to build old-format archives by default.
+ */
+#ifndef BUILDOLDPKGFORMAT
+#define BUILDOLDPKGFORMAT 0
+#endif
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..36f526a
--- /dev/null
+++ b/configure
@@ -0,0 +1,2374 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.4 
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/usr
+ac_help="$ac_help
+  --with-arch=value       set/override (Debian) architecture value"
+ac_help="$ac_help
+  --with-newdeb           make dpkg-deb default to new archives"
+ac_help="$ac_help
+  --with-olddeb           make dpkg-deb default to old archives"
+ac_help="$ac_help
+  --with-newdeb           make dpkg-deb default to new archives"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Initialize some other variables.
+subdirs=
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -build | --build | --buil | --bui | --bu | --b)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=PREFIX    install architecture-dependent files in PREFIX
+                          [same as prefix]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+--enable and --with options recognized:$ac_help
+EOF
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.4"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *) 
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=include/dpkg.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  if test "${CFLAGS+set}" != set; then
+    echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_gcc_g=yes
+else
+  ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+    echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
+    if test $ac_cv_prog_gcc_g = yes; then
+      CFLAGS="-g -O"
+    else
+      CFLAGS="-O"
+    fi
+  fi
+else
+  GCC=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if ${CXX-g++} -E conftest.C 2>&5 | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+  if test "${CXXFLAGS+set}" != set; then
+    echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_gxx_g=yes
+else
+  ac_cv_prog_gxx_g=no
+fi
+rm -f conftest*
+
+fi
+    echo "$ac_t""$ac_cv_prog_gxx_g" 1>&6
+    if test $ac_cv_prog_gxx_g = yes; then
+      CXXFLAGS="-g -O"
+    else
+      CXXFLAGS="-O"
+    fi
+  fi
+else
+  GXX=
+  test "${CXXFLAGS+set}" = set || CXXFLAGS="-g"
+fi
+
+
+# Check whether --with-arch or --without-arch was given.
+withval="$with_arch"
+if test -n "$withval"; then
+  
+ if test "x$with_arch" = x; then
+  { echo "configure: error: --with-arch requires an architecture name" 1>&2; exit 1; }
+ fi
+ cat >> confdefs.h <<EOF
+#define ARCHITECTURE "${with_arch}"
+EOF
+
+
+else
+  
+ echo $ac_n "checking system architecture""... $ac_c" 1>&6
+ dpkg_archwhy=''
+ if eval "test \"`echo '$''{'dpkg_cv_arch'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  dpkg_arch="`dpkg --print-architecture 2>/dev/null`"
+  if test "x$dpkg_arch" != x; then
+   dpkg_archwhy="  (obtained from dpkg)"
+  elif test "${GCC-no}" = yes; then
+   dpkg_arch="`$(CC) --print-libgcc-file-name |
+       sed -e 's,^.*/gcc-lib/,,; s,/libgcc\.a$,,; s,/[0-9.][0-9.]*$,,; s/-.*$//'`"
+   if test "x`echo \"$dpkg_arch\" | tr -d a-z0-9-`" != x -o "x$dpkg_arch" = x
+   then
+    dpkg_arch=""
+    dpkg_archwhy=" (bad output from --print-libgcc-file-name)"
+   else
+    dpkg_arch2="`sed -e '/^'$dpkg_arch'[       ]/!d; s/^[-0-9a-z]*[     ]*//' \
+                    $srcdir/archtable`"
+    if test "x$dpkg_arch2" = "x$dpkg_arch"; then
+     dpkg_archwhy=" (obtained from gcc)"
+    elif test "x$dpkg_arch2" != x; then
+     dpkg_archwhy=" (from gcc, canonical form of $dpkg_arch)"
+     dpkg_arch="$dpkg_arch2"
+    else
+     dpkg_archwhy=" (from gcc, but not in archtable)"
+    fi
+   fi
+  else
+   dpkg_archwhy=''
+  fi
+  dpkg_cv_arch="$dpkg_arch"
+fi
+
+ if test "x$dpkg_cv_arch" != x; then
+  echo "$ac_t"""$dpkg_cv_arch$dpkg_archwhy"" 1>&6
+  cat >> confdefs.h <<EOF
+#define ARCHITECTURE "${dpkg_cv_arch}"
+EOF
+
+ else
+  echo "$ac_t"""failed$dpkg_archwhy"" 1>&6
+ fi
+
+fi
+
+# Check whether --with-newdeb or --without-newdeb was given.
+withval="$with_newdeb"
+if test -n "$withval"; then
+  
+ cat >> confdefs.h <<\EOF
+#define BUILDOLDPKGFORMAT 0
+EOF
+
+
+else
+  
+ # Check whether --with-olddeb or --without-olddeb was given.
+withval="$with_olddeb"
+if test -n "$withval"; then
+  
+  cat >> confdefs.h <<\EOF
+#define BUILDOLDPKGFORMAT 1
+EOF
+
+
+else
+  
+  case "$CC" in
+  /*)
+   pathccompiler="$CC"
+   ;;
+  *)
+   # Extract the first word of ""$CC"", so it can be a program name with args.
+set dummy "$CC"; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_path_pathccompiler'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$pathccompiler" in
+  /*)
+  ac_cv_path_pathccompiler="$pathccompiler" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_pathccompiler="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+pathccompiler="$ac_cv_path_pathccompiler"
+if test -n "$pathccompiler"; then
+  echo "$ac_t""$pathccompiler" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+   ;;
+  esac
+  echo $ac_n "checking .deb format to build by default""... $ac_c" 1>&6
+  if file "$pathccompiler" 2>/dev/null | grep ELF >/dev/null 2>&1; then
+   echo "$ac_t""new (C compiler looks like ELF)" 1>&6
+   cat >> confdefs.h <<\EOF
+#define BUILDOLDPKGFORMAT 0
+EOF
+
+  else
+   echo "$ac_t""old (C compiler not ELF)" 1>&6
+   cat >> confdefs.h <<\EOF
+#define BUILDOLDPKGFORMAT 1
+EOF
+
+  fi
+
+fi
+
+fi
+
+
+# Check whether --with-newdeb or --without-newdeb was given.
+withval="$with_newdeb"
+if test -n "$withval"; then
+  cat >> confdefs.h <<\EOF
+#define BUILDOLDPKGFORMAT 0
+EOF
+
+fi
+
+
+
+echo $ac_n "checking for /usr/bin/perl""... $ac_c" 1>&6
+if test -f /usr/bin/perl
+then
+       echo "$ac_t""yes" 1>&6
+       perlpath=/usr/bin/perl
+       
+else
+       echo "$ac_t""no" 1>&6
+       # Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_path_perlpath'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$perlpath" in
+  /*)
+  ac_cv_path_perlpath="$perlpath" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_perlpath="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+perlpath="$ac_cv_path_perlpath"
+if test -n "$perlpath"; then
+  echo "$ac_t""$perlpath" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 774 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 788 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 822 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  ac_cv_c_cross=no
+else
+  ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+cross_compiling=$ac_cv_c_cross
+echo "$ac_t""$ac_cv_c_cross" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 843 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 865 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 883 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  ac_cv_header_stdc=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 904 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      for ac_prog in ginstall installbsd scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           # OSF/1 installbsd also uses dspmsg, but is usable.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_ifs"
+  # As a last resort, use the slow shell script.
+  test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh"
+fi
+  INSTALL="$ac_cv_path_install"
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1037 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "mode_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_mode_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+  cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1068 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pid_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_pid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1099 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "size_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1130 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+char vprintf(); 
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1178 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+char _doprnt(); 
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero;
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 1302 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() { return 0; }
+int t() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 1318 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() { return 0; }
+int t() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  ac_cv_c_bigendian=yes
+else
+  rm -rf conftest*
+  ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 1347 "configure"
+#include "confdefs.h"
+main () {
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+fi
+rm -fr conftest*
+fi
+fi
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+  cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo $ac_n "checking size of unsigned long""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 1386 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned long));
+  exit(0);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  ac_cv_sizeof_unsigned_long=`cat conftestval`
+else
+  ac_cv_sizeof_unsigned_long=0
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+EOF
+
+
+echo $ac_n "checking size of unsigned int""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 1420 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned int));
+  exit(0);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  ac_cv_sizeof_unsigned_int=`cat conftestval`
+else
+  ac_cv_sizeof_unsigned_int=0
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
+EOF
+
+
+for ac_func in unsetenv alphasort scandir strerror strsignal strtoul
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1453 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+char $ac_func(); 
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/cdefs.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1505 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for sysinfo""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_sysinfo'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1539 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char sysinfo(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+char sysinfo(); 
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_sysinfo) || defined (__stub___sysinfo)
+choke me
+#else
+sysinfo();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+  rm -rf conftest*
+  eval "ac_cv_func_sysinfo=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_func_sysinfo=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'sysinfo`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SYSINFO 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking __NR_sysinfo""... $ac_c" 1>&6
+  cat > conftest.$ac_ext <<EOF
+#line 1581 "configure"
+#include "confdefs.h"
+
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+#ifdef __NR_sysinfo
+ yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes; tsk tsk - get your libc fixed." 1>&6
+    cat >> confdefs.h <<\EOF
+#define HAVE_NRSYSINFO 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+    echo "configure: warning: sysinfo missing; compilation of dpkg proper may fail." 1>&2
+fi
+rm -f conftest*
+
+fi
+
+
+
+if test "${GCC-no}" = yes; then
+ CFLAGS=-O2; OPTCFLAGS=-O3
+else
+ CFLAGS=-O
+fi
+
+
+
+
+ echo $ac_n "checking your C compiler""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_c_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1626 "configure"
+#include "confdefs.h"
+#include <string.h>
+int main() { return 0; }
+int t() {
+strcmp("a","b")
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_works=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_works=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_c_works" = xyes; then
+  true
+  echo "$ac_t""works" 1>&6
+ else
+  true
+  echo "$ac_t""broken" 1>&6
+ { echo "configure: error: C compiler is broken" 1>&2; exit 1; }
+ fi
+
+
+
+ echo $ac_n "checking alphasort declaration""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_header_alphasort'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1663 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/dir.h>
+
+int main() { return 0; }
+int t() {
+alphasort
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_header_alphasort=yes
+else
+  rm -rf conftest*
+  dpkg_cv_header_alphasort=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_header_alphasort" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALPHASORT_DECLARATION 1
+EOF
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+
+ echo $ac_n "checking inlines""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_c_inline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1706 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+} inline int foo (int x) {
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_inline=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_inline=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_c_inline" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_INLINE 1
+EOF
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+
+ echo $ac_n "checking __attribute__((,,))""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_c_attribute_supported'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1746 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+extern int testfunction(int x) __attribute__((,,))
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_attribute_supported=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_attribute_supported=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_c_attribute_supported" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_GNUC25_ATTRIB 1
+EOF
+
+  
+ echo $ac_n "checking __attribute__((noreturn))""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_c_attribute_noreturn'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1780 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+extern int testfunction(int x) __attribute__((noreturn))
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_attribute_noreturn=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_attribute_noreturn=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_c_attribute_noreturn" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+#define HAVE_GNUC25_NORETURN 1
+EOF
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+  
+ echo $ac_n "checking __attribute__((const))""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_c_attribute_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1819 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+extern int testfunction(int x) __attribute__((const))
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_attribute_const=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_attribute_const=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_c_attribute_const" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+#define HAVE_GNUC25_CONST 1
+EOF
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+  
+ echo $ac_n "checking __attribute__((format...))""... $ac_c" 1>&6
+ if eval "test \"`echo '$''{'dpkg_cv_attribute_format'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 1858 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+extern int testfunction(char *y, ...) __attribute__((format(printf,1,2)))
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_attribute_format=yes
+else
+  rm -rf conftest*
+  dpkg_cv_attribute_format=no
+fi
+rm -f conftest*
+
+fi
+
+ if test "x$dpkg_cv_attribute_format" = xyes; then
+  true
+  echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+#define HAVE_GNUC25_PRINTFFORMAT 1
+EOF
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+ else
+  true
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+
+CWARNS=""
+
+
+
+
+ echo $ac_n "checking GCC warning flag(s) -Wall -Wno-implicit""... $ac_c" 1>&6
+ if test "${GCC-no}" = yes
+ then
+  if eval "test \"`echo '$''{'dpkg_cv_c_gcc_warn_all'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wall -Wno-implicit -Werror"
+   cat > conftest.$ac_ext <<EOF
+#line 1912 "configure"
+#include "confdefs.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main() { return 0; }
+int t() {
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_all=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_all=no
+fi
+rm -f conftest*
+
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$dpkg_cv_c_gcc_warn_all" = xyes; then
+   CWARNS="${CWARNS} -Wall -Wno-implicit"
+   echo "$ac_t""ok" 1>&6
+  else
+   dpkg_cv_c_gcc_warn_all=''
+   echo "$ac_t""no" 1>&6
+  fi
+ else
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+ echo $ac_n "checking GCC warning flag(s) -Wwrite-strings""... $ac_c" 1>&6
+ if test "${GCC-no}" = yes
+ then
+  if eval "test \"`echo '$''{'dpkg_cv_c_gcc_warn_writestrings'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wwrite-strings -Werror"
+   cat > conftest.$ac_ext <<EOF
+#line 1959 "configure"
+#include "confdefs.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main() { return 0; }
+int t() {
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_writestrings=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_writestrings=no
+fi
+rm -f conftest*
+
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$dpkg_cv_c_gcc_warn_writestrings" = xyes; then
+   CWARNS="${CWARNS} -Wwrite-strings"
+   echo "$ac_t""ok" 1>&6
+  else
+   dpkg_cv_c_gcc_warn_writestrings=''
+   echo "$ac_t""no" 1>&6
+  fi
+ else
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+ echo $ac_n "checking GCC warning flag(s) -Wpointer-arith""... $ac_c" 1>&6
+ if test "${GCC-no}" = yes
+ then
+  if eval "test \"`echo '$''{'dpkg_cv_c_gcc_warn_pointerarith'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wpointer-arith -Werror"
+   cat > conftest.$ac_ext <<EOF
+#line 2006 "configure"
+#include "confdefs.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main() { return 0; }
+int t() {
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_pointerarith=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_pointerarith=no
+fi
+rm -f conftest*
+
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$dpkg_cv_c_gcc_warn_pointerarith" = xyes; then
+   CWARNS="${CWARNS} -Wpointer-arith"
+   echo "$ac_t""ok" 1>&6
+  else
+   dpkg_cv_c_gcc_warn_pointerarith=''
+   echo "$ac_t""no" 1>&6
+  fi
+ else
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+ echo $ac_n "checking GCC warning flag(s) -Wimplicit -Wnested-externs""... $ac_c" 1>&6
+ if test "${GCC-no}" = yes
+ then
+  if eval "test \"`echo '$''{'dpkg_cv_c_gcc_warn_implicit'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wimplicit -Wnested-externs -Werror"
+   cat > conftest.$ac_ext <<EOF
+#line 2053 "configure"
+#include "confdefs.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main() { return 0; }
+int t() {
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_implicit=yes
+else
+  rm -rf conftest*
+  dpkg_cv_c_gcc_warn_implicit=no
+fi
+rm -f conftest*
+
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$dpkg_cv_c_gcc_warn_implicit" = xyes; then
+   CWARNS="${CWARNS} -Wimplicit -Wnested-externs"
+   echo "$ac_t""ok" 1>&6
+  else
+   dpkg_cv_c_gcc_warn_implicit=''
+   echo "$ac_t""no" 1>&6
+  fi
+ else
+  echo "$ac_t""no" 1>&6
+ fi
+
+
+if test "${GCC-no}" = yes; then
+ CWARNS="${CWARNS} -Wmissing-prototypes -Wstrict-prototypes"
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
+  >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.4"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile dpkg-deb/Makefile lib/Makefile include/Makefile
+          dselect/Makefile split/Makefile methods/Makefile
+          md5sum/Makefile main/Makefile doc/Makefile scripts/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status. 
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; 
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@pathccompiler@%$pathccompiler%g
+s%@perlpath@%$perlpath%g
+s%@CPP@%$CPP%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@OPTCFLAGS@%$OPTCFLAGS%g
+s%@CWARNS@%$CWARNS%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile dpkg-deb/Makefile lib/Makefile include/Makefile
+          dselect/Makefile split/Makefile methods/Makefile
+          md5sum/Makefile main/Makefile doc/Makefile scripts/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust relative srcdir, etc. for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  cp $ac_given_srcdir/$ac_file_in conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status. 
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+# Maximum number of lines to put in a single here document.
+ac_max_here_lines=12
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..0fe0f9e
--- /dev/null
@@ -0,0 +1,242 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(include/dpkg.h)
+AC_CONFIG_HEADER(config.h)
+
+AC_PREFIX_DEFAULT(/usr)
+
+AC_PROG_CC
+AC_PROG_CXX
+
+AC_ARG_WITH(arch,
+[  --with-arch=value       set/override (Debian) architecture value],
+[
+ if test "x$with_arch" = x; then
+  AC_MSG_ERROR(--with-arch requires an architecture name)
+ fi
+ AC_DEFINE_UNQUOTED(ARCHITECTURE, "${with_arch}")
+],[
+ AC_MSG_CHECKING(system architecture)
+ dpkg_archwhy=''
+ AC_CACHE_VAL(dpkg_cv_arch,[
+  dpkg_arch="`dpkg --print-architecture 2>/dev/null`"
+  if test "x$dpkg_arch" != x; then
+   dpkg_archwhy="  (obtained from dpkg)"
+  elif test "${GCC-no}" = yes; then
+changequote(, )dnl
+   dpkg_arch="`$(CC) --print-libgcc-file-name |
+       sed -e 's,^.*/gcc-lib/,,; s,/libgcc\.a$,,; s,/[0-9.][0-9.]*$,,; s/-.*$//'`"
+changequote([, ])dnl
+   if test "x`echo \"$dpkg_arch\" | tr -d a-z0-9-`" != x -o "x$dpkg_arch" = x
+   then
+    dpkg_arch=""
+    dpkg_archwhy=" (bad output from --print-libgcc-file-name)"
+   else
+changequote(, )dnl
+    dpkg_arch2="`sed -e '/^'$dpkg_arch'[       ]/!d; s/^[-0-9a-z]*[     ]*//' \
+                    $srcdir/archtable`"
+changequote([, ])dnl
+    if test "x$dpkg_arch2" = "x$dpkg_arch"; then
+     dpkg_archwhy=" (obtained from gcc)"
+    elif test "x$dpkg_arch2" != x; then
+     dpkg_archwhy=" (from gcc, canonical form of $dpkg_arch)"
+     dpkg_arch="$dpkg_arch2"
+    else
+     dpkg_archwhy=" (from gcc, but not in archtable)"
+    fi
+   fi
+  else
+   dpkg_archwhy=''
+  fi
+  dpkg_cv_arch="$dpkg_arch"
+ ])
+ if test "x$dpkg_cv_arch" != x; then
+  AC_MSG_RESULT("$dpkg_cv_arch$dpkg_archwhy")
+  AC_DEFINE_UNQUOTED(ARCHITECTURE, "${dpkg_cv_arch}")
+ else
+  AC_MSG_RESULT("failed$dpkg_archwhy")
+ fi
+])
+AC_ARG_WITH(newdeb,
+[  --with-newdeb           make dpkg-deb default to new archives],
+[
+ AC_DEFINE(BUILDOLDPKGFORMAT, 0)
+],[
+ AC_ARG_WITH(olddeb,
+[  --with-olddeb           make dpkg-deb default to old archives],
+[
+  AC_DEFINE(BUILDOLDPKGFORMAT, 1)
+],
+[
+  case "$CC" in
+  /*)
+   pathccompiler="$CC"
+   ;;
+  *)
+   AC_PATH_PROG(pathccompiler,"$CC")
+   ;;
+  esac
+  AC_MSG_CHECKING(.deb format to build by default)
+  if file "$pathccompiler" 2>/dev/null | grep ELF >/dev/null 2>&1; then
+   AC_MSG_RESULT([new (C compiler looks like ELF)])
+   AC_DEFINE(BUILDOLDPKGFORMAT, 0)
+  else
+   AC_MSG_RESULT([old (C compiler not ELF)])
+   AC_DEFINE(BUILDOLDPKGFORMAT, 1)
+  fi
+])])
+
+AC_ARG_WITH(newdeb,
+[  --with-newdeb           make dpkg-deb default to new archives],
+[AC_DEFINE(BUILDOLDPKGFORMAT, 0)])
+
+
+AC_MSG_CHECKING(for /usr/bin/perl)
+if test -f /usr/bin/perl
+then
+       AC_MSG_RESULT(yes)
+       perlpath=/usr/bin/perl
+       AC_SUBST(perlpath)
+else
+       AC_MSG_RESULT(no)
+       AC_PATH_PROG(perlpath,perl)
+fi
+
+AC_STDC_HEADERS
+AC_PROG_INSTALL
+dnl AC_PROGRAM_PATH(GZIP, gzip, )   use these from $PATH
+dnl AC_PROGRAM_PATH(TAR, tar, )     use these from $PATH
+AC_PROG_RANLIB
+AC_MODE_T
+AC_PID_T
+AC_SIZE_T
+AC_VPRINTF
+AC_C_CONST
+AC_C_BIGENDIAN
+AC_CHECK_SIZEOF(unsigned long)
+AC_CHECK_SIZEOF(unsigned int)
+AC_CHECK_FUNCS(unsetenv alphasort scandir strerror strsignal strtoul)
+AC_CHECK_HEADERS(sys/cdefs.h)
+
+AC_CHECK_FUNC(sysinfo,
+  AC_DEFINE(HAVE_SYSINFO),
+  AC_MSG_CHECKING(__NR_sysinfo)
+  AC_EGREP_CPP(yes, [
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+#ifdef __NR_sysinfo
+ yes
+#endif
+],
+    AC_MSG_RESULT([yes; tsk tsk - get your libc fixed.])
+    AC_DEFINE(HAVE_NRSYSINFO),
+    AC_MSG_RESULT(no)
+    AC_MSG_WARN([sysinfo missing; compilation of dpkg proper may fail.])))
+
+AC_SUBST(OPTCFLAGS)
+if test "${GCC-no}" = yes; then
+ CFLAGS=-O2; OPTCFLAGS=-O3
+else
+ CFLAGS=-O
+fi
+
+dnl DPKG_CACHED_TRY_COMPILE(<description>,<cachevar>,<include>,<program>,<ifyes>,<ifno>)
+define(DPKG_CACHED_TRY_COMPILE,[
+ AC_MSG_CHECKING($1)
+ AC_CACHE_VAL($2,[
+  AC_TRY_COMPILE([$3],[$4],[$2=yes],[$2=no])
+ ])
+ if test "x$$2" = xyes; then
+  true
+  $5
+ else
+  true
+  $6
+ fi
+])
+
+DPKG_CACHED_TRY_COMPILE(your C compiler,dpkg_cv_c_works,
+ [#include <string.h>], [strcmp("a","b")],
+ AC_MSG_RESULT(works),
+ AC_MSG_RESULT(broken)
+ AC_MSG_ERROR(C compiler is broken))
+
+DPKG_CACHED_TRY_COMPILE(alphasort declaration,dpkg_cv_header_alphasort,[
+#include <sys/types.h>
+#include <sys/dir.h>
+], alphasort,
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ALPHASORT_DECLARATION),
+ AC_MSG_RESULT(no))
+
+DPKG_CACHED_TRY_COMPILE(inlines,dpkg_cv_c_inline,,
+ [} inline int foo (int x) {],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INLINE),
+ AC_MSG_RESULT(no))
+
+DPKG_CACHED_TRY_COMPILE(__attribute__((,,)),dpkg_cv_c_attribute_supported,,
+ [extern int testfunction(int x) __attribute__((,,))],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_GNUC25_ATTRIB)
+  DPKG_CACHED_TRY_COMPILE(__attribute__((noreturn)),dpkg_cv_c_attribute_noreturn,,
+   [extern int testfunction(int x) __attribute__((noreturn))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_NORETURN),
+   AC_MSG_RESULT(no))
+  DPKG_CACHED_TRY_COMPILE(__attribute__((const)),dpkg_cv_c_attribute_const,,
+   [extern int testfunction(int x) __attribute__((const))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_CONST),
+   AC_MSG_RESULT(no))
+  DPKG_CACHED_TRY_COMPILE(__attribute__((format...)),dpkg_cv_attribute_format,,
+   [extern int testfunction(char *y, ...) __attribute__((format(printf,1,2)))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_PRINTFFORMAT),
+   AC_MSG_RESULT(no)),
+ AC_MSG_RESULT(no))
+
+AC_SUBST(CWARNS)
+CWARNS=""
+
+dnl DPKG_C_GCC_TRY_WARNS(<warnings>,<cachevar>)
+define(DPKG_C_GCC_TRY_WARNS,[
+ AC_MSG_CHECKING([GCC warning flag(s) $1])
+ if test "${GCC-no}" = yes
+ then
+  AC_CACHE_VAL($2,[
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} $1 -Werror"
+   AC_TRY_COMPILE([
+#include <string.h>
+#include <stdio.h>
+],[
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+], [$2=yes], [$2=no])
+   CFLAGS="${oldcflags}"])
+  if test "x$$2" = xyes; then
+   CWARNS="${CWARNS} $1"
+   AC_MSG_RESULT(ok)
+  else
+   $2=''
+   AC_MSG_RESULT(no)
+  fi
+ else
+  AC_MSG_RESULT(no, not using GCC)
+ fi
+])
+
+DPKG_C_GCC_TRY_WARNS(-Wall -Wno-implicit, dpkg_cv_c_gcc_warn_all)
+DPKG_C_GCC_TRY_WARNS(-Wwrite-strings, dpkg_cv_c_gcc_warn_writestrings)
+DPKG_C_GCC_TRY_WARNS(-Wpointer-arith, dpkg_cv_c_gcc_warn_pointerarith)
+DPKG_C_GCC_TRY_WARNS(-Wimplicit -Wnested-externs, dpkg_cv_c_gcc_warn_implicit)
+
+if test "${GCC-no}" = yes; then
+ CWARNS="${CWARNS} -Wmissing-prototypes -Wstrict-prototypes"
+fi
+
+AC_OUTPUT(Makefile dpkg-deb/Makefile lib/Makefile include/Makefile
+          dselect/Makefile split/Makefile methods/Makefile
+          md5sum/Makefile main/Makefile doc/Makefile scripts/Makefile)
diff --git a/debian.Changelog b/debian.Changelog
new file mode 100644 (file)
index 0000000..0a1bd71
--- /dev/null
@@ -0,0 +1,1253 @@
+dpkg (1.1.4); priority=MEDIUM
+
+  * Allow overwriting of conflicting packages being removed.  (Bug#2614.)
+
+  * a.out control file says Pre-Depends: libc4 | libc.  (Bug#2640.)
+  * ELF control file and libc dependencies changed to use finalised scheme.
+  * ELF control file and libc dependencies for i386 only.  (Bug#2617.)
+
+  * Guidelines say use only released libraries and compilers.
+  * Install wishlist as /usr/doc/dpkg/WISHLIST.
+  * Remove spurious entries for Guidelines in info dir file.
+
+  * dpkg-deb --build checks permissions on control (DEBIAN) directory.
+
+  * Spaces in control file fields not copied by dpkg-split.  (Bug#2633.)
+  * Spaces in split file part control data ignore.  (Bug#2633.)
+
+  * Portability fixes, including patch from Richard Kettlewell.
+  * Fixed minor configure.in bug causing mangled GCC -W options.
+
+ -- Ian Jackson <ian@chiark.chu.cam.ac.uk>  Thu, 4 Apr 1996 01:58:40 +0100
+
+dpkg (1.1.3); priority=LOW
+
+  * dselect disk methods support Pre-Depends installation ordering.
+  * When dpkg fails and --auto-deconfigure would help it says so.
+  * dpkg --search output lists several packages with same file on one line.
+  * Improved dpkg usage message somewhat.
+
+  * dpkg-deb --build checks permissions and types of maintainer scripts.
+  * dpkg-deb --build treats misspecified conffiles as error, not warning.
+  * dpkg --print-architecture prints compiler's architecture while
+    dpkg --version (&c) print system's arch (this to help cross-compiling).
+  * More minor guidelines changes, including dir entry fixup.
+
+  * configure script caches more values.
+  * Changed maintainer email address to ian@chiark.chu.cam.ac.uk.
+
+ -- Ian Jackson <ian@chiark.chu.cam.ac.uk>  Sat, 16 Mar 1996 19:18:08 +0000
+
+dpkg (1.1.2); priority=LOW
+
+  * Packaging guidelines installed properly (and as guidelines
+    rather than debian-guidelines).
+  * ELF version has more checks to stop you wrecking your dpkg installation.
+  * dselect disk methods now look for a `local' tree as well, for
+    people who want locally-available software of various kinds.
+  * dpkg-divert has debugging message removed.
+  * Minor guidelines changes.
+
+  * Various makefile cleanups, mainly to do with ELF vs. a.out support.
+  * debian.rules cleans out ~ files itself, as well as calling make clean.
+  * debian.rules names .nondebbin.tar.gz file ELF too, if appropriate.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 14 Mar 1996 03:38:29 +0000
+
+dpkg (1.1.1elf); priority=LOW
+
+  * Added /usr/lib/dpkg/elf-executables-ok and elf-in-kernel.
+  * Replaces field now allows automatic removal of conflicting packages.
+  * Replaces field now required to overwrite other packages' files.
+  * Architecture field, and dpkg --print-architecture, supported.
+  * build new format archives by default when compiled with ELF compiler.
+
+  * symlinks are now installed atomically (good for shared libraries).
+  * create /var/lib/dpkg/diversions in postinst if necessary (Bug#2465.)
+  * Pre-Depends now correctly fails if package never configured.
+  * dselect disk methods mount with -o nosuid,nodev.
+  * update-rc.d defaults doesn't add both K and S in any one runlevel;
+    dpkg postinst fixes up this situation if it sees it.
+
+  * Assorted fixups to the Guidelines, which are now in one piece.
+  * dpkg --list prints version string in one piece.
+  * dpkg-scanpackages doesn't produce notice on output with list of
+    packages with Section and/or Priority control file fields.
+
+  * control file and debian.rules work both for ELF and non-ELF compiles.
+  * most files compiled with -O2 (-O3 only for some critical files) -
+    this fixes ELF build.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 11 Mar 1996 04:25:28 +0000
+
+dpkg (1.1.0); priority=LOW
+
+  * dpkg supports Pre-Depends.
+  * postinst script gets most-recently-configured version as $2.
+
+  * lib/tarfn.c #includes <errno.h> (portability fix).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 11 Feb 1996 21:07:03 +0000
+
+dpkg (1.0.17); priority=LOW
+
+  * dpkg --recursive follows symlinks (useful for devel tree).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sat, 10 Feb 1996 15:58:46 +0000
+
+dpkg (1.0.16); priority=LOW
+
+  * dpkg-deb much faster reading new format archives.  (Bug#2256.)
+  * Developers' documentation in /usr/doc/dpkg/, /usr/info/.
+
+  * Fixed typo in control file Description.
+
+  * configure script tries to improve matters wrt sysinfo.
+  * any debian-tmp.deb is deleted by `./debian.rules clean'.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 4 Feb 1996 15:51:59 +0000
+
+dpkg (1.0.15); priority=LOW
+
+  * dselect disk methods should never unmount things they didn't mount.
+  * debian.README aka /usr/doc/copyright updated.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 30 Jan 1996 15:05:39 +0000
+
+dpkg (1.0.14); priority=MEDIUM
+
+  * fixed file descriptor leak in dpkg introduced in 1.0.11.
+  * included dpkg-name in this package (conflicts with dpkg-name).
+
+  * redraw in dselect main menu changed to use clearok (like in lists).
+  * sa_restorer in struct sigaction no longer used (portability fix).
+  * removed Guidelines from source package.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 30 Jan 1996 02:52:29 +0000
+
+dpkg (1.0.13); priority=MEDIUM
+
+  * dselect partition and mounted methods work again.
+  * dpkg-deb --no-act in usage message.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 26 Jan 1996 18:37:03 +0000
+
+dpkg (1.0.12); priority=MEDIUM (HIGH for users of 1.0.11)
+
+  * Fixed frequent dpkg coredump introduced in 1.0.11.  (Bug#2219.)
+  * dpkg-deb ensures version numbers start with alphanumerics.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 24 Jan 1996 00:42:31 +0000
+
+dpkg (1.0.11); priority=MEDIUM
+
+  * corrected potentially serious problem with dpkg low-memory in-core
+    files database.
+  * dpkg-split --msdos puts output files in right directory.  (Bug#2165.)
+
+  * diversions implemented - see `dpkg-divert --help'.
+
+  * dselect shows and uses (for dependencies) currently installed
+    version of a package if that is more recent.
+  * dpkg --force-... options are in separate help screen.
+  * better error messages for corrupted .deb archives.  (Bug#2178.)
+  * dselect NFS method will unmount correct copy of NFS area if mounted
+    twice.
+
+  * removes some ELF compilation warnings.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 19 Jan 1996 02:41:46 +0000
+
+dpkg (1.0.10); priority=MEDIUM
+
+  * dpkg-deb option parsing unmuddled (-I option was removed
+    in 1.0.9 and broke dpkg-deb).  (Bug#2124.)
+
+  * dpkg-split will work when ELF `ar' is installed, and is faster.
+
+  * nfs dselect method now available.
+  * disk methods don't prompt spuriously for Packages files.
+  * cdrom+harddisk methods can find Packages files.
+
+  * dpkg-scanpackages (creates Packages files) now in /usr/sbin.
+
+  * various changes to help compilation of dpkg-deb, dpkg-split
+    and md5sum on non-Debian systems.
+  * <sys/fcntl.h> replaced by <fcntl.h> throughout.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 14 Jan 1996 02:55:19 +0000
+
+dpkg (1.0.9); priority=MEDIUM
+
+  * dselect uninitialised variable coredump fixed (thanks Carl).
+
+  * version numbers printed by --version fixed.  (Bug#2115.)
+  * disk method problem with missing Packages files fixed.  (Bug#2114.)
+  * dependency version relationships now <= >= << >> =.  (Bug#2060.)
+
+  * install-info is in /usr/sbin, not /usr/bin.  (Bug#1924.)
+  * dpkg regards Revision field as obsolete.
+
+  * <asm/unistd.h> changed to <linux/unistd.h> (for m68k port).
+  * scripts/Makefile.in `clean' target deletes scripts.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 11 Jan 1996 20:51:20 +0000
+
+dpkg (1.0.8); priority=LOW
+
+  * update-alternatives slightly more helpful message.  (Bug#1975.)
+  * cosmetic improvements to disk installation method.  (Bug#1970,1956.)
+  * mounted filesystem and unmounted partition separate methods.  (Bug#1957.)
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 12 Dec 1995 04:07:47 +0000
+
+dpkg (1.0.7); priority=MEDIUM (HIGH to upgrade syslogd)
+
+  * dselect harddisk/CDROM method script handles multiple package
+    areas.
+  * Everything has a manpage, though many are very unhelpful indeed.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 30 Nov 1995 03:59:14 +0000
+
+dpkg (1.0.6); priority=MEDIUM (HIGH to upgrade syslogd)
+
+  * conffiles can now be taken over properly from one package by
+    another which replaces it.  (Bug#1482.)
+  * dpkg will not deconfigure essential packages when --auto-deconfigure
+    is set (this bug was fairly unlikely ever to be exercised).
+
+  * dpkg checks for the presence of certain important programs on the PATH.
+  * dselect is now more informative when a dependency is missing, saying
+    "<package> does not appear to be available".  (Bug#1642, 1705).
+
+  * `make distclean' fixed; config.* &c removed from source archive.
+  * lib/lock.c now uses fcntl rather than flock, for better portability.
+
+  * `Package_Revision: 0' removed from control file.
+  * Some inaccuracies and bad formatting in various messages corrected.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 21 Nov 1995 20:15:18 +0000
+
+dpkg (1.0.5); priority=LOW
+
+  * dpkg-split allows some space for the header.  (Bug#1649.)
+  * dpkg-split now has --msdos option for 8.3 filenames.
+  * dpkg-split --join &c will not complain about trailing garbage.
+
+  * dselect & dpkg will no longer ignore SIGHUP will running subprocesses.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 13 Oct 1995 13:59:51 +0100
+
+dpkg (1.0.4); priority=MEDIUM (HIGH for dselect users with 1.0.3)
+
+  * fixed bug which prevented dselect from displaying the bottom line of
+    any listing screen.  This was introduced in 1.0.3, sorry !
+
+  * a conffile will never cause a prompt if the package maintainer
+    distributes a file identical to the user's, even if the file has
+    been edited by both the user and the maintainer or is a
+    newly-registered conffile.  (Bug#1639.)
+
+  * dselect disk/cdrom method script says where to get Packages file.
+  * dselect help has better descriptions of the functions of Return and Q.
+
+  * postinst now warns about some problems with /usr/lib/dpkg/methods/hd.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 12 Oct 1995 01:45:38 +0100
+
+dpkg (1.0.3); priority=MEDIUM
+
+  * dselect: fixed segfault when doing some multiple (de)selections.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 10 Oct 1995 03:21:12 +0100
+
+dpkg (1.0.2); priority=MEDIUM
+
+  * problem with screen refresh after `o' (change order) corrected.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 9 Oct 1995 13:11:04 +0100
+
+dpkg (1.0.1); priority=LOW
+
+  * much better dpkg performance on low-memory systems.
+  * start-stop-daemon --name should now work. (oops!)
+  * fixed typo which could turn into memory overwriting bug sometime.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 8 Oct 1995 20:12:29 +0100
+
+dpkg (1.0.0); priority=LOW
+
+  * Version 1.0.0: dpkg is no longer beta.
+
+  * tar extractor no longer looks up an empty string using getgrnam
+    (this causes the libc to coredump when using NIS).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 1 Oct 1995 13:07:36 +0100
+
+dpkg (0.93.80); priority=LOW
+
+  * dselect help screen intro changed to remove `much' before `help'.
+
+  * update-alternatives.pl contains hardcoded ENOENT value, instead
+    of requiring POSIX.pm to be present.
+
+  * Makefiles changed to strip when installing instead of when building.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sat, 30 Sep 1995 01:44:12 +0100
+
+dpkg (0.93.79) BETA; priority=LOW
+
+  * DPKG_NO_TSTP environment variable which stops dpkg sending the
+    process group a SIGTSTP (Bug#1496).
+  * End key should work in dselect lists (Bug#1501).
+  * various message typos (missing \n's) fixed (Bug#1504).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 29 Sep 1995 03:27:01 +0100
+
+dpkg (0.93.78) BETA; priority=LOW
+
+  * dselect keystrokes help file typo fix.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 28 Sep 1995 20:31:02 +0100
+
+dpkg (0.93.77) BETA; priority=MEDIUM
+
+  * dpkg --remove --pending will purge things when appropriate.
+
+  * fixed failure to null-terminate dpkg conflict problem messages.
+  * fixed bug in formatting of dependency version problem messages.
+
+  * Conffiles resolution prompt for new conffile: typo fixed.
+  * Changed dpkg usage error to suggest `-Dhelp' instead of `--Dhelp'.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 20 Sep 1995 23:44:35 +0100
+
+dpkg (0.93.76) BETA; priority=MEDIUM
+
+  * dpkg --auto-deconfigure option (used automatically by dselect) allows
+    `important' packages which many others depend on to be split.
+  * dpkg should no longer fail an assertion during complicated
+    multiple configurations involving packages which are on hold.
+
+  * update-alternatives supports negative priorities.
+  * /etc/alternatives is included in the .deb archive.
+
+  * Package priorities changed: Required (Req), Important (Imp), Standard (Std),
+    Optional (Opt) and Extra (Xtr).  For backward compatibility Base is an
+    alias for Required, and Recommended is kept as a level just below Standard.
+
+  * dselect shows introductory help screen when entering package lists (both
+    main and recursive).
+  * dselect help messages made more friendly.
+  * dselect package list `quit, confirm, and check dependencies' key is
+    now Return rather than lowercase `q'; likewise method list `select this
+    one and configure it' key.
+  * dselect selects packages with priority `standard' or better by default.
+  * dselect `v=verbose' becomes `v=terse' when in verbose mode.
+
+  * hard disk method unmounts /var/lib/dpkg/methods/mnt on failure.
+  * disk methods' install message uses `stty' to find out what the
+    interrupt character is, and uses that in the prompt (rather than ^C).
+  * dpkg now tolerates ^Z characters in Packages files.
+  * harddisk method doesn't display extra slash when updating packages file.
+  * harddisk method burbles less if it doesn't have a good default.
+
+  * dpkg-deb now supports new flexible format, but old format still default.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 20 Sep 1995 02:49:41 +0100
+
+dpkg (0.93.75) BETA; priority=MEDIUM
+
+  * dselect no longer segfaults when you try to modify the last item.
+
+  * dselect Makefile compiles with -g, and links without -s, but installs
+    with -s, so that built source directory has debugabble binary.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 12 Sep 1995 02:59:29 +0100
+
+dpkg (0.93.74) BETA; priority=LOW
+
+  * dpkg-split implemented and installed in /usr/bin/dpkg-split.
+    (NB this is not compatible with Carl Streeter's old dpkg-split script.)
+  * dpkg uses dpkg-split.
+  * floppy disk method available - NB this is a first attempt only.
+
+  * hard disk method uses --merge-avail rather than --update-avail.
+  * installation by default of `standard' packages removed again.
+    (I don't think this is the right place to do this.)
+  * update-alternatives --remove correctly deletes all slave links;
+    minor cosmetic improvements.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 11 Sep 1995 02:06:05 +0100
+
+dpkg (0.93.73) BETA; priority=LOW
+
+  * dselect multi-package selection now done by `divider' lines
+    actually in the package list, rather than horizontal highlight
+    movement.
+  * dselect help available, and keybindings rationalised.
+
+  * postinst removes /usr/lib/dpkg/methods/hd if upgrading from
+    0.93.42.3 or earlier.
+  * `hold' flag changed to be settable by the user only, and
+    made orthogonal to the `reinstallation required' flag.
+  * dpkg will install by default any packages with priority of
+    `standard' or better unless they're explictly deselected.
+
+  * dselect dependency/conflict resolution will suggest marking absent
+    packages for `purge' rather than `deinstall'.
+  * disk method script produces message about invoking dpkg.
+  * dpkg produces warning, not error, when it gets EPERM trying to
+    remove a directory belonging to a package being removed.
+  * dpkg, dpkg-deb usage error reporting improved.
+  * dselect detects too-dumb terminals and stops.
+  * dpkg-deb(8) updated a little (thanks to Bill Mitchell).
+
+  * dselect debugmake script uses -O0.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 10 Sep 1995 12:23:05 +0100
+
+dpkg (0.93.72) BETA; priority=MEDIUM
+
+  * /usr/sbin/update-alternatives added.
+
+  * New names for certain control file fields (old names work
+    as aliases): Optional -> Suggests, Recommended -> Recommends,
+    Class -> Priority.
+     
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 3 Sep 1995 16:37:41 +0100
+
+dpkg (0.93.71) BETA; priority=LOW
+
+  * dpkg doesn't silently overwrite `new' conffiles (Bug#1283).
+  * case now not significant in Essential, Status and Class (Bug#1280).
+  * dselect checks method scripts for execute, not for write.
+
+  * spelling fixes in lib/dbmodify.c and dselect/helpmsgs.src.
+
+  * dselect `clean' target deletes helpmsgs.cc and helpmsgs.cc.new.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 31 Aug 1995 13:56:08 +0100
+
+dpkg (0.93.70) BETA; priority=MEDIUM
+
+  * dselect unmounted harddisk method has many silly bugs fixed.
+
+  * dpkg --root option restored (was removed by mistake in 0.93.68).
+  * minor cosmetic change to dselect subprocess failure message.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 9 Aug 1995 22:18:55 +0100
+
+dpkg (0.93.69) BETA; priority=MEDIUM
+
+  * dpkg --configure and --remove should work properly when
+    they have to defer processing (this tends to happen when many
+    packages are processed at once).  (Bug#1209.)
+
+  * dpkg --configure and --remove work better when `processing'
+    several related packages with --no-act.
+
+  * dpkg --auto is now two options, --pending or -a (for configure,
+    remove, &c) and --recursive or -R (for install, unpack, &c).
+
+  * dpkg debug options in usage message, and values available (-Dh).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 9 Aug 1995 22:18:55 +0100
+
+dpkg (0.93.68) BETA; priority=MEDIUM
+
+  * dpkg won't get an internal error if you try to use the default
+    conffiles response (ie, if you just hit return).  (Bug#1208.)
+
+  * dselect hard disk and CD-ROM methods - the real thing, but ALPHA.
+
+  * dselect allows you to go straight to `update' or `install' if
+    you have already set up an access method.
+  * new dpkg options --yet-to-unpack, --merge-avail and --update-avail.
+  * dpkg -G is an abbreviation for dpkg --refuse-downgrade.
+  * dpkg -R alias for --root withdrawn, pending reuse with different meaning.
+  * dpkg --help message rationalised somewhat.
+
+  * Obsolete `examples' and `dpkg-split' directories removed from
+    source tree.  The `hello' package is a better example.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 7 Aug 1995 02:16:25 +0100
+
+dpkg (0.93.67) BETA; priority=LOW for C dpkg alpha testers, HIGH for others
+
+  * dpkg no longer statically linked and -g.
+  * calls to abort() changed to print string, file and line number first.
+  * removed unused variable from dpkg source.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 4 Aug 1995 01:39:52 +0100
+
+dpkg (0.93.66) ALPHA; priority=MEDIUM
+
+  * dpkg will correctly remove overwritten files from the lists of
+    the package(s) that used to contain them.
+
+  * dpkg --purge is now an action, rather than a modifier for --remove,
+    and the -P alias for it is withdrawn.
+
+  * dpkg --unpack/--install filenames in messages are now more sensible
+    about when to use .../ (show as many trailing components as possible
+    in 40 characters, or the whole path if that the last component is
+    longer than that).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 3 Aug 1995 02:11:03 +0100
+
+dpkg (0.93.65) ALPHA; priority=MEDIUM
+
+  * dpkg --remove should, when a package being removed is depended-on
+    by another that is also queued for removal, defer the depended-on
+    package rather than aborting it.  (Bug#1188.)
+
+  * dpkg will not attempt to configure or remove a package more than
+    once in the same run.  (Bug#1169.)
+
+  * dpkg cosmetic fix to dependency problems message (this bug
+    hasn't been triggered to my knowledge).
+
+  * perl-dpkg no longer installed in /usr/bin.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 2 Aug 1995 13:02:58 +0100
+
+dpkg (0.93.64) ALPHA; priority=MEDIUM
+
+  * dpkg marks a package as no longer `to be configured in this run'
+    when an error occurs, so that other packages which depend on it
+    will fail (rather than causing a loop and an assertion failure,
+     packages.c:166: failed assertion `dependtry <= 4').
+
+  * dselect initial selection granularity is single-package.
+  * dpkg --no-also-select option renamed to --selected-only (old option
+    still accepted, but no longer in --help).  Changed -N to -O.
+
+  * dselect `update' option changed to `install' (and other options
+    renamed too).  NB: old access methods will not work, because
+    the `update' script should now be an `install' script.
+
+  * dselect `installation methods' renamed to `access methods'.
+  * dpkg --skip-same-version and --refuse-downgrade produce friendlier
+    messages when they skip packages.
+  * --licence option now properly mentioned in all programs' --version
+    messages.
+
+  * bad fix for ELF compile problem involving myopt.h removed (compile
+    problem turned out to be a GCC bug.)
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 1 Aug 1995 03:03:58 +0100
+
+dpkg (0.93.63) ALPHA; priority=LOW
+
+  * preinst works around shell bug/misfeature involving `trap'.
+
+  * dpkg --skip-same-version doesn't skip packages which have
+    an error flag set or which aren't in a standard `installed' state.
+
+  * dpkg --search now does a substring search if the string doesn't
+    start with a wildcard character (*, [ or ?) or slash.
+
+  * problem with C/C++ linkage of stuff in "myopt.h" fixed, to help
+    with compiling with GCC 2.7.0.
+
+  * dselect Makefile.in `clean' deletes curkeys.inc &c, so that they are
+    not shipped in the distribution source and will be rebuilt on the
+    target system.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 27 Jul 1995 13:38:47 +0100
+
+dpkg (0.93.62) ALPHA; priority=HIGH
+
+  * dpkg purges leftover control scripts from /var/lib/dpkg/tmp.ci,
+    rather than associating them with the wrong package.  (Bug#1101.)
+
+  * dpkg won't `disappear' packages containing no files or directories,
+    nor a package required for depends/recommended.  (Bug#1128.)
+
+  * dpkg follows directory symlinks.  (Bug#1125.)
+
+  * dselect fixups for ELF/GCC2.7.0 compilation.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 21 Jul 1995 21:43:41 +0100
+
+dpkg (0.93.61) ALPHA; priority=LOW
+
+  * dselect keybindings and status characters and descriptions changed
+    (in pursuance of Bug#1037, user interface problems, still open.)
+
+  * Some cleanups to fix mistakes discovered by ELF-GCC 2.7.0, and fixup
+    for newer C++ draft standard (`for' variable declaration scope change).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 18 Jul 1995 01:42:51 +0100
+
+dpkg (0.93.60) ALPHA; priority=HIGH
+
+  * dpkg doesn't think packages have `disappeared' if you install
+    several packages at once.  (later reported as Bug#1132.)
+
+  * usage error messages tidied up.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 16 Jul 1995 17:56:56 +0100
+
+dpkg (0.93.59) ALPHA; priority=HIGH
+
+  * dpkg doesn't break maintainer scripts &c if package `foo' exists
+    when processing package `foobar'.  (Related to Bug#1101.)
+
+  * dpkg implements `disappear' functionality.
+  * dpkg/dselect remove dead entries from /var/lib/dpkg/status.
+
+  * dpkg --list now sorted correctly and output somewhat improved.
+  * some debugging messages moved from dbg_stupidlyverbose to dbg_scripts.
+  * dpkg prints `Removing foo' message even if foo is not configured.
+  * dpkg only prints `serious warning: files list file ... missing'
+    once for each package.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 16 Jul 1995 02:32:11 +0100
+
+dpkg (0.93.58) ALPHA; priority=HIGH
+
+  * dpkg should write out status even for packages which it has only
+    encountered in the `available' file so far.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 14 Jul 1995 20:19:21 +0100
+
+dpkg (0.93.57) ALPHA; priority=LOW
+
+  * dpkg does chroot when running maintainer scripts (--instdir
+    should work right now, though I haven't been able to test it).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 14 Jul 1995 01:32:30 +0100
+
+dpkg (0.93.56) ALPHA; priority=HIGH
+
+  * dpkg can now overwrite symlinks to directories, and will
+    do correct handling of symlinks to plain files.
+  * dpkg should not replace any directory with a symlink.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 13 Jul 1995 02:43:36 +0100
+
+dpkg (0.93.55) ALPHA; priority=MEDIUM
+
+  * dpkg can now extract hardlinks.
+  * dpkg configuration/removal works in the presence of dependency cycles.
+  * dpkg should no longer fail an assertion at processarc.c:193.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Wed, 12 Jul 1995 01:34:44 +0100
+
+dpkg (0.93.54) ALPHA; priority=MEDIUM
+
+  * dpkg and dselect no longer throw away all Class and Section
+    information in /var/lib/dpkg/available.  (Oops.)
+  * dpkg --refuse-<something> now works (this broke some dselect
+    method scripts' attempts to use --refuse-downgrade).
+  * dpkg --audit and --list implemented.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 10 Jul 1995 00:35:13 +0100
+
+dpkg (0.93.53) ALPHA; priority=LOW
+
+  * dpkg --install/--unpack only skips on-hold packages with --auto.
+  * dpkg doesn't fclose() the --fsys-tarfile pipe twice.
+  * dpkg error handling and reporting cleaned up.
+  * dpkg now lists any failed packages/files just before exiting.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 9 Jul 1995 16:31:36 +0100
+
+dpkg (0.93.52) ALPHA; priority=MEDIUM
+
+  * dpkg won't segfault due to missing (Package_)Revision fields.
+  * dpkg --search works.
+  * dpkg will set execute permissions on scripts if necessary.
+  * dpkg prints filenames in --unpack and --install.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sat, 8 Jul 1995 12:41:39 +0100
+
+dpkg (0.93.51) ALPHA; priority=HIGH
+
+  * dpkg --status and --listfiles now work.
+
+  * dpkg --remove --auto won't try to remove everything (!)
+  * dpkg --unpack doesn't coredump after unpacking the first package.
+  * dpkg won't fail an assertion if it bombs out of --configure
+    or --remove because of too many errors.
+
+  * Support for `Essential' in dpkg (not yet in dselect).
+  * `available' (Packages) file class and section override those
+    from package control files.
+  * `Essential: yes' added to control file.
+
+  * Locking strategy changed, now uses flock (no more stale locks).
+  * preinst now more helpful about conffiles upgrade problem.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sat, 8 Jul 1995 01:15:26 +0100
+
+dpkg (0.93.50) ALPHA
+
+  * C dpkg now in service.
+
+  * dselect now installs in /usr/bin instead of /usr/sbin.
+  * Improved `explanation of display' help and changed HSOC to EIOW.
+  * dselect goes back to top of info display when you move the
+    highlight.
+
+  * Added <sys/types.h> to md5sum/md5.c, for the benefit of FreeBSD.
+  * --admindir doesn't append `var/lib/dpkg' to its argument.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 19 May 1995 21:03:08 +0100
+
+dpkg (0.93.42.3) BETA; priority=LOW
+
+  * Rebuilt using ncurses 1.9.2c-0.
+  * Silenced `subcritical error' message if errno == ENOENT.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 12 Jun 1995 13:09:24 +0100
+
+dpkg (0.93.42.2) BETA; priority=HIGH
+
+  * install-info --remove properly removes multi-line entries.
+  * Slightly changed ^L redraw code in dselect package list.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sat, 10 Jun 1995 14:06:01 +0100
+
+dpkg (0.93.42.1) BETA; priority=HIGH esp. for new installations
+
+  * update-rc.d default no longer adds K entries in runlevels 2345.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 6 Jun 1995 18:56:23 +0100
+
+dpkg (0.93.42) BETA; priority=LOW; HIGH for dselect users
+
+  * Fix unitialised variable reference bug in dselect (#890).
+  * Fix problem with wordwrapping package and method descriptions.
+  * Create /var/lib/dpkg/methods/mnt.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 19 May 1995 21:03:08 +0100
+
+dpkg (0.93.41) BETA; priority=LOW
+
+  * Create /var/lib/dpkg/methods.
+  * dpkg.pl noisily ignores --skip-same-version rather than barfing.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 16 May 1995 13:28:27 +0100
+
+dpkg (0.93.40) BETA; priority=LOW
+
+  * dselect's subprogram failure message made to stand out more.
+
+  * When switching out of curses, always move the cursor to the
+    bottom right corner of the screen.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Tue, 16 May 1995 01:03:38 +0100
+
+dpkg (0.93.39) BETA; priority=LOW
+
+  * dselect can now:
+    - allow you to select and configure an installation method;
+    - invoke installation method scripts to update the available file
+      and unpack packages;
+    - invoke dpkg to configure and remove packages.
+    There are no installation methods available yet.
+
+  * Search feature in dselect works (it was purely an ncurses bug).
+
+  * dpkg-*.nondebbin.tar.gz now available (built by debian.rules).
+
+  * The target directory for dpkg-deb --extract (also available as
+    dpkg --extract) is no longer optional.  dpkg-deb suggests the use
+    of dpkg --install if you omit it.
+
+  * Added <errno.h> to lib/lock.c and fixed ref. to `byte' in
+    md5sum/md5.c, for portability to Solaris 2.
+
+  * Rebuilt `configure' and `config.h.in' using autoconf 2.3.
+  * Revised function attribute support checking in configure script.
+  * Removed obsolete `dselect.pl' from scripts directory.
+  * New option --licence on all the C programs.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Sun, 14 May 1995 18:05:38 +0100
+
+dpkg (0.93.38) BETA; priority=MEDIUM
+
+  * Version number comparisons (in dpkg and dselect) now >= <=
+    as documented (Bug#831; thanks to Christian Linhart).
+
+  * dselect now has a non-superuser readonly mode.
+  * dselect doesn't pop up unsatisfied `Optional's when quitting.
+  * `unable to delete saved old file' message fixed dpkg_tmp to dpkg-tmp.
+
+  * Made dpkg convert `revision' to `package_revision' when reading
+    (eg) the `status' file.  libdpkg.a has `revision' as a synonym
+    for `package_revision' and writes the former.
+
+  * Major improvements and many changes to C option parsing, database
+    management, error handling, Makefiles &c to support dpkg.
+  * dpkg-deb should now work if sizeof(void*) < sizeof(void(*)()).
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Mon, 24 Apr 1995 12:34:39 +0100
+
+dpkg (0.93.37) BETA; priority=LOW (MEDIUM for dselect users)
+
+  * Fixed segfault if no description available (Bug#735);
+    thanks to Peter Tobias for the bug report.
+  * Fixed other assorted minor bugs in description displays.
+
+  * Changed dpkg-deb --info short option from -i to -I, to make
+    it unique across dpkg and dpkg-deb (-i still works with
+    dpkg-deb for backwards compatibility).
+
+  * Produce more sensible error when main package list is empty.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Fri, 7 Apr 1995 02:24:55 +0100
+
+dpkg (0.93.36) BETA; priority=LOW (MEDIUM for dselect users)
+
+  * All the C code (including dselect) updated to support `provides'
+    (virtual packages).
+  * Revamped dselect's related package selection/deselection
+    algorithms.
+  * Everything can now handle arbitrary `class' values (as well
+    as the predefined ones which we understand and can interpret).
+  * Fixed bug that prevented display update when moving down a small
+    recursive package list in dselect.
+  * Column heading characters corrected from `SHOC' to `HSOC'.
+
+ -- Ian Jackson <iwj10@cus.cam.ac.uk>  Thu, 6 Apr 1995 12:48:13 +0100
+
+dpkg (0.93.35) BETA; priority=MEDIUM
+
+ * Preserve ownerships and permissions on configuration files.
+ * Fix bug in conffile updating that could leave a hardlink
+   <foo>.dpkg-new to the conffile <foo>.
+
+ * Improved dselect's package list help messages.
+ * Highlight now moves on after (de)selecting just one package.
+ * Better algorithm for scrolling up/down when moving highlight.
+ * Fixed bug in display of `preformatted' extended Description lines.
+   (dselect is still ALPHA, but is fairly stable.)
+
+ * Improved dpkg's message when configuring a package that doesn't
+   exist, and when selecting or skipping a package that isn't
+   currently selected (during unpack processing).
+
+ * Description in control file expanded.
+
+ * Scroll back to top when changing what is in the `info' area.
+
+dpkg (0.93.34) BETA; priority=LOW (HIGH for dselect users)
+
+ * dselect: Fixed bug which caused a coredump if you exited the
+   package list if you'd made any changes.  Ouch !
+
+ * dselect: Improved selection algorithm to show fewer extraneous
+   packages; improved display for unavailable packages.
+
+ * dpkg: Improved progress messages during unpacking somewhat.
+
+dpkg (0.93.33) BETA; priority=LOW (HIGH for dselect users)
+
+ * dselect now has a main menu.
+
+ * Fixed nasty uninitialised data bug in dselect.
+
+ * dselect now locks and unlocks the packages database.
+
+Mon, 27 Mar 1995 03:30:51 BST  Ian Jackson <iwj10@cus.cam.ac.uk>
+
+       * dpkg (0.93.32): Alpha dselect released and installed in
+                         /usr/sbin/dselect.
+       * dpkg (0.93.32): Many portability enhancements: should now
+                         compile using GCC 2.6.3, and dpkg-deb should
+                         compile better on non-Linux systems.
+       * dpkg (0.93.32): dpkg will not loop if its stdin disappears
+                         and it needs to prompt.
+       * dpkg (0.93.32): Fixed removal dependency error to show
+                         correct package (Bug #648).
+       * dpkg (0.93.32): Tidied up copyright notices.
+       * dpkg (0.93.32): First draft of update-rc.d manpage, not yet
+                         installed in /usr/man.
+       * dpkg (0.93.32): Changes to top-level Makefile.in to improve
+                         error trapping.
+       * dpkg (0.93.32): Improved Makefile `clean' and `distclean'
+                         targets.
+       * dpkg (0.93.32): Deleted irrelevant `t.c' from lib and
+                         dselect directories.
+       * dpkg (0.93.32): Added vercmp.c with version comparison code.
+       * dpkg (0.93.32): varbufextend message changed - varbufs not
+                         just for input buffers.
+       * dpkg (0.93.32): varbuf has C++ member functions in header
+                         #ifdef __cplusplus.
+
+Changes in dpkg 0.93.31:
+
+* start-stop-daemon --pidfile now works (Bug#571).
+* Fixed dependency processing bugs which could require a rerun of
+  dpkg --configure (Bug#566).
+* Fixed garbage output for `language' of control file in dpkg-deb --info.
+
+Changes in dpkg 0.93.30:
+
+* Added /usr/sbin/start-stop-daemon.
+
+Changes in dpkg 0.93.29:
+
+* Made postinst scripts really be run when dpkg --purge used.
+* Added new --force-extractfail option - VERY DANGEROUS.
+
+Changes in dpkg 0.93.28:
+
+* Removed undef of %xx_p21 in read_database_file, which caused the
+  the whole status database to become trashed when any update files
+  were read.
+* Make infinite-loop prevention and cycle detection work.
+* Made findbreakcycle work (ie, break properly when cycle detected).
+* New script, update-rc.d, to update links /etc/rc?.d/[KS]??*.
+* dpkg.pl now sets the umask to 022.
+* Cosmetic error message fix to dpkg-deb.
+* Deleted OLD directory altogether.
+* Improved error-trapping in top-level Makefile loops.
+
+Changes in dpkg 0.93.27:
+
+* Make version number specifications in Depends &c work.
+* Added AC_PROG_CXX to autoconf.in for dselect.
+* Changed myopt.h not to have cipaction field in cmdinfo (this was
+  specially for dpkg-deb) - now we have a generic void*.
+* Renamed `class' member of `pkginfoperfile' to `clas' [sic].
+* Much work in `dselect' subdirectory.
+* Deleted executables, objects and libraries from OLD tree !
+* Minor changes to various copyright notices and top-of-file comments.
+* Don't install nasty Perl dselectish thing as /usr/bin/dselect.
+
+Changes in dpkg 0.93.26:
+
+* Added --no-also-select instead of not auto-selecting on --unpack
+  but doing so on --install; removed --force-unpack-any.
+
+Changes in dpkg 0.93.25:
+
+* Fixed duplicate output (failure to flush before fork) bug.
+* More clarification of md5sum.c copyright.
+* Corrected typo in ChangeLog in 0.93.24 source package.
+
+Changes in dpkg 0.93.24:
+
+* dpkg could copy conffiles info from one package to another.  Aargh.
+  Bug #426.
+* dpkg failed to initialise status if you tried to remove or
+  configure a nonexistent package.  Bug #419.
+* install-info now handles START-INFO-DIR-ENTRY entries like:
+   * Gdb::                         The GNU debugger.
+  Previously it would only accept (Bug #407):
+   * Gdb: (gdb).                   The GNU debugger.
+* When installing a new foo.info[.gz], install-info now replaces
+   * Foo: (foo.info).              The Gnoo Foo.
+  as well as just * Foo: (foo). ...
+* Moved option parsing out of dpkg-deb into libdpkg.
+* Assorted minor source code rearrangements.
+* Fixed assorted copyright notices, clarified md5sum copyright.
+* Corrected typo in 0.93.23 source package's ChangeLog.
+
+Changes in dpkg 0.93.23:
+
+* `dpkg-deb' --build now does a syntax check on the control file.
+* `dselect' is now no longer called `debian', spurious copy removed
+  from package top-level source directory.
+* C control information parsing complete and somewhat tested.
+* Moved `global' include files into $(srcdir)/include from ../lib,
+  added some files to the lib Makefile, and arranged for pop_cleanup().
+
+Changes in dpkg 0.93.22:
+
+* Fixed bug which caused dpkg to see failures of md5sum where there
+  were none (would also have caused dpkg to miss a real failure).
+* Fixed failure to update some `status' database fields.
+
+Changes in dpkg 0.93.21:
+
+* Fixed error-handling bug which could corrupt database.
+
+Changes in dpkg 0.93.20:
+
+* Fixed bug which ran old (/var/adm/dpkg) postinst scripts.
+* Fixed dpkg usage message which claimed -i => both --install & --info.
+* Use Colin Plumb's MD5 code - faster, and better copyright.
+* Manpages: dpkg-deb(8), deb-control(5), deb(5) - thanks to Raul
+  Deluth Miller.  Also, an xfig picture of some C program innards.
+
+Changes in dpkg 0.93.19:
+
+* Don't delete the `list' file from the dpkg database.
+* Fixed various bugs in the conffile handling.
+* Conffiles that are symlinks will now be treated as if the
+  `dereferenced' name of the file was listed in conffiles.  This means
+  that /etc/foo -> /usr/etc/foo will cause all conffile updates of
+  /etc/foo to create /usr/etc/foo.dpkg-tmp &c instead.  However, the
+  link will be removed if --purge is used to delete all the conffiles.
+* When doing a new installation, or when updating a conffile that
+  wasn't listed as a conffile in the old version of the package, don't
+  do any prompting but just install the version from the archive.
+* Corrected error message if exec of dpkg --vextract failed
+  and --instroot or --root specified.
+* Added new --force-unpack-any option.
+* Extra newline after --status output.
+* Added -W options to CFLAGS.
+* Fixed mistake in previous ChangeLog entry.
+
+Changes in dpkg 0.93.18:
+
+* Fixed invocation of dpkg-deb --vextract if --root or --instdir
+  not specified.
+* Create /var/lib/dpkg/updates.
+
+Changes in dpkg 0.93.17:
+
+* install-info --remove exits with status 0 if it doesn't find the
+  thing to remove, instead of status 1.
+* Error handling functions have __attribute__((format...)) if GCC.
+* push_cleanup its arg takes void **argv instead of char **argv.
+* Top-level Makefile.in has set -e before `for' loops.
+* dpkg-deb --info not-an-existing-file produces fewer error messages.
+
+Changes in dpkg 0.93.16:
+
+* Made --root= option really extract to $instroot instead of `/'.
+* install-info clears the 0444 bits in its umask.
+* Fixed a few database handling bugs which cause dpkg always to fail,
+  and usually to corrupt the status database in various ways.
+* dpkg-deb completely rewritten, now doesn't tinker with
+  /var/{adm,lib}/dpkg.  Should be faster.
+* Directory structure and Makefiles in source package reorganised.
+
+Changes in dpkg 0.93.15:
+
+* Added `debian' (dselect), still very primitive.
+* Database format changed, and moved from /var/adm to /var/lib.
+* Added dpkg --avail mode, --list, --status and --search.
+* Set of dpkg => dpkg-deb pass-through operations changed (but
+  dpkg-deb not yet updated).
+* Added --root, --admindir and --instdir, as well as --isok &c.
+* Moved much stuff into /usr/lib/dpkg-lib.pl, rewritten status
+  database handling.
+* Put packages in `purge' state even if `deinstall' requested if
+  they have no postrm and no conffiles.
+* Version number comparisons fixed.
+* insert-version.pl now installes lib.pl filename too.
+* Strip trailing slashes when reading files from file lists.
+
+Changes in dpkg 0.93.14:
+
+* Fixed parsing of DEPENDS &c fields with trailing whitespace.
+* postinst now fixes up broken ispell.control file.
+* Cyclic dependency/multiple package removal processing: don't consider
+  packages we've just removed when looking for a reason not to go ahead.
+* Added call to postinst with `purge' argument for expunging old
+  configuration etc. that aren't listed in conffiles.
+
+Changes in dpkg 0.93.13:
+
+* sub S_ISREG defined in dpkg.pl.
+* Checking of DEPENDS &c fields was too lax, causing an internal error
+  if you fed it certain kinds of broken control file.
+* Fixed misleading message from bogus installationstatus call.
+* New -u and -U options to dpkg-deb which don't unpack the /DEBIAN
+  directory, and use these in dpkg.pl; clean up /DEBIAN in postinst.
+
+Changes in dpkg 0.93.12:
+
+* No longer needs *.ph files, since these appear to be broken.
+* Postinst fixes up *.control files with curly brackets.
+* embryo of dselect.
+
+Changes in dpkg 0.93.11:
+
+* New --ignore-depends option.
+* This ChangeLog changed format here.
+
+Wed Nov 30 15:38:21 GMT 1994  Ian Jackson  <iwj10@cus.cam.ac.uk>
+
+       * dpkg 0.93.11 released.
+
+       * conffile updating fixed.
+
+       * Message `updgrade' in dpkg changed to `replace'.
+
+       * install-info now copes with multi-line entries.
+
+       * version numbers now done automatically in dpkg and install-info.
+
+       * more debugging around conffiles updates.
+
+       * *.hash files not deleted so soon.
+
+       * adds brand new packages to status array so we can install them.
+
+       * postinst does h2ph for {sys,linux}/{stat,types}.ph if required.
+
+Mon Nov 28 02:00:13 GMT 1994  Ian Jackson  <iwj10@cus.cam.ac.uk>
+
+        * dpkg 0.93.10 released.
+
+        * dpkg.pl completely rewritten.
+
+        * dpkg-deb: removed dabase-processing and --install option.
+
+        * Makefiles reworked, debian.rules added.
+
+        * Don't install anything in /usr/doc/examples.
+
+        * dpkg-*.deb contains /usr/bin/dpkg-deb.dist, fixed up by postinst.
+
+Thu Oct 20 13:22:20 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg 0.93.9 released.
+
+        * dpkg.pl: Use $argument, not $package, with `--build'.
+        Make sure that saved postinst scripts are executable.
+
+Tue Oct 18 09:40:57 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg 0.93.8 released.
+
+        * deb/remove.c (pkg_remove): Do not report an error from rmdir ()
+        when `errno' is ENOTEMPTY (Directory not empty), because in this
+        case we have found the highest-level directory in the package and
+        are ready to exit the loop (i.e., it is a normal occurrence).
+
+Mon Oct 17 10:44:32 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * Makefile.in: Adapted all Makefiles to the GNU Coding Standards.
+
+        * deb/remove.c (pkg_remove): Make sure that parent directories are
+        removed LAST!  This will result in complete removal of packages
+        when --remove is called.  dpkg 0.93.7 (and earlier) had problems
+        with this because it tried to remove directories in order, which
+        will work most of the time, but not necessarily all of the time.
+
+        * deb/list.c (pkg_list): Output is sorted by package name.
+
+Tue Oct  4 12:27:10 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * deb/contents.c (pkg_contents): When a list file cannot be
+        opened, silently fail and let the front-end explain the problem.
+
+        * deb/util.c (return_info): When a control file cannot be opened,
+        silently fail and let the front-end explain the problem.
+
+        * deb/search.c (pkg_search): Exit 0 if the regular expression is
+        matched and 1 if it is not.
+
+Mon Oct  3 18:38:53 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg.pl: New file.  Replaces dpkg.sh.
+
+        * deb/Makefile.in: Renamed `dpkg-util.deb' to `dpkg-deb'.
+
+        * deb/build.c (pkg_build): `--build' is less verbose, instead
+        letting the front-end add verbosity where appropriate.
+
+        * deb/install.c (pkg_install): Ditto.
+
+        * deb/remove.c (pkg_remove): Ditto.
+
+        * deb/search.c (pkg_search): Ditto.
+
+        * deb/describe.c (pkg_describe): `--describe' is less verbose,
+        instead letting the front-end add verbosity where appropriate.
+        The ``Description:'' label has been removed.
+
+        * deb/version.c (pkg_version): `--version' is less verbose,
+        instead letting the front-end add verbosity where appropriate.
+        The ``Version:'' label has been removed, as has the maintainer
+        information.
+
+Mon Sep 12 14:22:04 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * deb/version.c (pkg_version): `--version' now reports the
+        version number of dpkg if no argument is specified.
+
+Thu Sep  1 13:31:37 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg 0.93.7 released.
+
+        * deb/build.c (pkg_build): check status and exit if non-zero.
+
+        * deb/contents.c (pkg_contents): ditto.
+
+        * deb/install.c (archive_extract): ditto.
+
+Thu Sep  1 13:20:08 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * deb/version.c (pkg_version): indent to the same point as
+        pkg_describe.
+
+Thu Sep  1 12:21:11 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * Makefile.in (dist): added debian.rules binary, source and
+        dist targets to make final distribution easier to make.
+        (install): install programs to /usr/bin.
+
+        * deb/Makefile.in (install): install programs to /usr/bin.
+
+        * deb/list.c (pkg_list): enforce a maximum limit of ten characters
+        for the package name in the output.
+        (pkg_list): left-justify the version number to make it easier for
+        the front-end to parse the output.
+        (pkg_list): replace first '\n' character in packages[n].description
+        with '\0'.
+
+        * deb/install.c (archive_extract): use the `p' option to `tar' to
+        ensure that permissions are preserved.
+
+Sat Aug 27 09:53:37 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg 0.93.6 released.
+
+        * deb/util.c (return_info): only unlink CONTROL if ARCHIVE_FLAG is
+        true!
+
+Fri Aug 26 15:38:22 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * dpkg 0.93.5 released.
+
+        * deb/contents.c (pkg_contents): merged function archive_contents
+        into function pkg_contents.
+
+        * deb/contents.c (pkg_contents): use lstat (rather than stat) so
+        that symbolic links are recognized.
+        (pkg_contents): print the usual `<path> -> <link_to>' now that we
+        recognize symbolic links.
+
+        * deb/util.c (return_info): create a FIFO to pipe the needed
+        information to the ``formatter'' rather than creating a directory
+        in /tmp for the package information, which is what we used to do.
+
+Thu Aug 25 11:46:27 1994  Ian Murdock  (imurdock@debra.debian.org)
+
+        * lib/fake-ls.c (mk_date_string): return a pointer to malloc'ed
+        area.
+        (mk_mode_string): ditto.
+
+        * dpkg.sh: make sure the control information is extracted to a
+        uniquely-named temporary directory during package installation.
+
+        * dpkg.sh: execute the pre- and post-removal scripts during
+        package removal.
+
+        * dpkg.sh: exit immediately if dpkg-util.deb reports failure.
+
+        * deb/install.c (pkg_control): make sure that `package' exists and
+        is a Debian archive before doing anything.
+
+        * deb/install.c (pkg_extract): make sure that `package' exists and
+        is a Debian archive before doing anything.
+
+        * deb/install.c (pkg_install): unlink `extract_output' when done.
+
+        * deb/remove.c (pkg_remove): use lstat (rather than stat) so that
+        --remove does not get confused and think that a symbolic link to a
+        directory is actually a directory, which results in the symbolic
+        link never being removed at all.
+
+ChangeLog begins Thu Aug 25 11:46:27 1994 for dpkg 0.93.5.
diff --git a/debian.README b/debian.README
new file mode 100644 (file)
index 0000000..027735c
--- /dev/null
@@ -0,0 +1,36 @@
+This is Debian/GNU Linux's package maintenance system.
+
+For an example of how to construct packages see the `hello' package
+which is part of Debian.
+
+[ Note for users of GCC 2.7.0: you must compile at least
+ `dselect/main.cc' with only -O2, due to a bug in GCC. ]
+
+Copyright (C) 1994,1995,1996 Ian Jackson <iwj10@cus.cam.ac.uk>
+Copyright (C) 1995 Bruce Perens <bruce@pixar.com>
+Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
+Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
+Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+Copyright (C) 1995,1996 Erick Branderhorst <branderhorst@heel.fgg.eur.nl>
+
+This 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 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 with
+your Debian GNU/Linux system, in /usr/doc/copyright/GPL, or with the
+dpkg source package as the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+/usr/bin/md5sum is compiled from md5.[ch] (written by Colin Plumb in
+1993 and modified by Ian Jackson in 1995) and md5sum.c (written by
+Branko Lankester in 1993 and modified by Colin Plumb in 1993 and Ian
+Jackson in 1995).  The sources and the binary are all in the public
+domain.
diff --git a/debian.control b/debian.control
new file mode 100644 (file)
index 0000000..19ffe29
--- /dev/null
@@ -0,0 +1,15 @@
+Package: dpkg
+Version: =elf
+Architecture: =
+Essential: yes
+Pre-Depends: libc5=, ncurses3.0
+Conflicts: dpkgname
+Replaces: dpkgname
+Maintainer: Ian Jackson <ian@chiark.chu.cam.ac.uk>
+Description: Package maintenance system for Debian GNU/Linux
+ This package contains the programs which handle the installation and
+ removal of packages on your system.
+ .
+ The primary interface for the dpkg suite is the `dselect' program;
+ a more low-level and less user-friendly interface is available in
+ the form of the `dpkg' command.
diff --git a/debian.controlaout b/debian.controlaout
new file mode 100644 (file)
index 0000000..d2827f9
--- /dev/null
@@ -0,0 +1,15 @@
+Package: dpkg
+Version: =
+Architecture: =
+Essential: yes
+Conflicts: dpkgname
+Replaces: dpkgname
+Pre-Depends: libc4 | libc
+Maintainer: Ian Jackson <ian@chiark.chu.cam.ac.uk>
+Description: Package maintenance system for Debian GNU/Linux
+ This package contains the programs which handle the installation and
+ removal of packages on your system.
+ .
+ The primary interface for the dpkg suite is the `dselect' program;
+ a more low-level and less user-friendly interface is available in
+ the form of the `dpkg' command.
diff --git a/debian.postinst b/debian.postinst
new file mode 100755 (executable)
index 0000000..aa1fd3a
--- /dev/null
@@ -0,0 +1,193 @@
+#!/bin/sh -
+
+set -e
+
+install-info --section Development Development \
+            --quiet /usr/info/guidelines.info.gz
+
+dupdaemonhelp () {
+       cat <<'END'
+
+Some daemons and similar services whose scripts have links in the
+/etc/rcN.d directories have both start (S) and stop (K) links in
+some runlevels.  Thus these services get stopped and immediately
+restarted at some runlevel changes, which is probably not what
+you want.  I can remove the probably-spurious K links if you like.
+
+Type Y to remove then, N to leave them, or L to list them.
+If you don't know what to do you can say N now and then delete
+them by hand later.
+
+END
+}
+
+if [ "x$1" = xconfigure ]; then case "$2" in 0.* | 1.0.* | 1.1.0 | 1.1.0[^0-9]* | '' )
+       for f in 0 1 2 3 4 5 6
+       do
+               cd /etc/rc$f.d
+               for g in K[0-9][0-9]*
+               do
+                       if [ -n "`echo \"x$g\" | tr -d 0-9A-Za-z_-`" ]
+                       then
+                               continue
+                       fi
+                       h="`echo $g | sed -e 's/^K/S/'`"
+                       if ! [ -L $h -a -L $g ] \
+                         || [ "`ls -Li $g 2>/dev/null | awk '{print $1}'`" != \
+                              "`ls -Li $h 2>/dev/null | awk '{print $1}'`" ]
+                       then
+                               continue
+                       fi
+                       removes="$removes rc$f.d/$g"
+               done
+       done
+       if [ -n "$removes" ]
+       then
+               cd /etc
+               dupdaemonhelp
+               while [ -n "$removes" ]
+               do
+                       echo -n 'y=remove, n=leave, l=list, h=help ?  '
+                       read response
+                       case "$response" in
+                       [Yy]*)
+                               echo "Removing duplicate K links ..."
+                               rm -v $removes
+                               removes=""
+                               ;;
+                       [Nn]*)
+                               echo -e "OK, leaving them.\n"
+                               removes=""
+                               ;;
+                       [Ll]*)
+                               echo
+                               echo $removes
+                               echo
+                               ;;
+                       [Hh]*)
+                               dupdaemonhelp
+                               ;;
+                       esac
+               done
+       fi
+;; esac ; fi
+
+cd /var/lib/dpkg
+if ! test -f diversions
+then
+       touch diversions
+fi
+
+cd /usr/bin
+if test dpkg-deb.dist -ef dpkg-deb; then rm dpkg-deb.dist; fi
+if test -f dpkg-deb.dist; then mv dpkg-deb.dist dpkg-deb; fi
+
+if test -d /DEBIAN
+then
+       echo 'Removing /DEBIAN directory which was created by a dpkg bug ...'
+       rm -r /DEBIAN
+fi
+
+if test -d /usr/lib/dpkg/methods/hd -a ! -x /usr/lib/dpkg/methods/hd/install
+then
+       echo \
+'Warning - /usr/lib/dpkg/methods/hd/ exists, but .../hd/install does not.
+This is probably left over from some previous manual installation of
+now-obsolete dselect-related software.  I suggest you remove the whole
+/usr/lib/dpkg/methods/hd directory and all its contents; otherwise dselect
+is unlikely to function correctly.'
+fi
+
+if test -f /var/lib/dpkg/status; then exit 0; fi
+
+cd /var/adm/dpkg
+
+if [ ! -f status ]
+then
+       echo 'Adding "status" file to dpkg system database ...'
+
+       rm -f /tmp/dpp.$$ || true
+
+       ls -1 deb/*.control >/tmp/dpp.$$
+       sed -e 's:^deb/::; s:\.control$: Install OK Installed:;' \
+               </tmp/dpp.$$ >status.new
+
+       rm /tmp/dpp.$$
+       mv status.new status
+fi
+
+if grep '{' deb/*.control >/dev/null
+then
+       echo 'Fixing up curly brackets in control files ...'
+       perl -i~ -pe \
+               'y/{}//d if m/^(depends|recommended|optional|conflicts):/i' \
+               deb/*.control
+       rm deb/*.control~
+fi
+
+if grep 'Optional: idanish ifrench' deb/ispell.control >/dev/null 2>&1
+then
+       echo 'Fixing up broken ispell.control file ...'
+       perl -i~ -pe 's/ /, /g, s/,// if m/^Optional:/' deb/ispell.control
+fi
+
+newdb=/var/lib/dpkg
+echo "Moving datatabase /var/adm/dpkg to $newdb and changing format ..."
+
+exec 4>$newdb/status.new
+exec 5<status
+
+while read <&5 package status
+do
+       echo " processing $package ..."
+       if test -f deb/$package.control
+       then
+               egrep . deb/$package.control >&4
+       else
+               echo >&4 "Package: $package"
+       fi
+       echo >&4 "Status: $status"
+       if test -f deb/$package.conffiles -a -s deb/$package.conffiles
+       then
+               echo >&4 "Conffiles:"
+               exec 6<deb/$package.conffiles
+               while read <&6 cfile
+               do
+                       expr match "$cfile" "[^         ]" >/dev/null || continue
+                       if test -f deb/$package.hash
+                       then
+                               hash="`grep \"^$cfile \" <deb/$package.hash || \
+                                       test $? = 1`"
+                       else
+                               hash=''
+                       fi
+                       test -n "$hash" || hash="$cfile -"
+                       expr match "$hash" / >/dev/null || hash="/$hash"
+                       echo >&4 " $hash"
+               done
+       elif test -f deb/$package.hash -a -s deb/$package.conffiles
+       then
+               echo >&4 "Conffiles:"
+               sed -ne '/^[^\/]/ s:^:/:; s/^/ /; / ./p' >&4 deb/$package.hash
+       fi
+       echo >&4
+       for s in {pre,post}{rm,inst} list
+       do
+               if test -f deb/$package.$s
+               then
+                       mv deb/$package.$s $newdb/info/$package.$s
+               fi
+       done
+done
+
+if ! test -f $newdb/available
+then
+       if test -f database
+       then
+               cp database $newdb/available
+       else
+               touch $newdb/available
+       fi
+fi
+
+mv $newdb/status.new $newdb/status
diff --git a/debian.preinst b/debian.preinst
new file mode 100755 (executable)
index 0000000..b7a3b21
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/sh -
+
+if [ "$1" != "upgrade" ]; then exit 0; fi
+
+set -e
+# i386elf: dpkg --assert-support-predepends
+
+oldver="$2"
+
+case "$oldver" in
+       0.93.[01234]* | - )     ;;
+       * )                     exit 0 ;;
+esac
+
+echo '
+contemplating upgrade of dpkg from pre-0.93.50 version ...'
+
+trap 'es=$?; rm -f /tmp/bp.$$; exit $es' 0
+
+perl -000 -ne 'print $x if m/^Package:\s+(\S+\n)/im &&
+                         ($x=$1) ne "dpkg\n" &&
+                         m/^Status:.*(unpacked|postinst)/im' \
+       /var/lib/dpkg/status >/tmp/bp.$$
+
+if test -s /tmp/bp.$$
+then
+       echo '
+
+WARNING - have you read the release notes for this upgrade ?
+
+The following packages have been unpacked but not yet configured:'
+       echo '' `cat /tmp/bp.$$`
+       echo -n '
+If you proceed with the dpkg upgrade with these packages in this state
+you will LOSE ANY CONFIGURATION CHANGES that have been made to their
+configuration files.  I recommend that you back out of the upgrade
+now (see below) and then configure each of these packages using:
+ dpkg --configure --force-hold <package>
+
+If you do this and it fails for some packages they are broken anyway, in
+which case you probably don'"'"'t have that much to lose by going ahead
+with the upgrade.
+
+Type "yes" to confirm that you really want to do the upgrade in
+spite of my warning above; if you give any other response we'"'"'ll back
+off the upgrade to give you a chance to fix things.
+
+Continue with upgrade despite probable loss of config data ? '
+       read response
+       case "$response" in
+       [Yy][Ye][Ss] )  echo OK ... ;;
+       * )             echo 'Aborting dpkg upgrade.'; exit 1 ;;
+       esac
+fi
+
+echo -n '
+IMPORTANT - you must install this upgrade on its own, not together in
+the same dpkg run as any other packages.  Otherwise you risk losing
+configuration information.
+
+If you say "no" to the question below we'"'"'ll back off the upgrade now,
+and you can then do it later using:
+ dpkg --install dpkg-0.93.51.deb
+If you'"'"'re not sure what to do, say "no", and then run that command
+(with the appropriate dpkg-*.deb filename) from a root shell prompt.
+
+Are you installing only the dpkg upgrade in this dpkg run ? [y/n] '
+read response
+case "$response" in
+[yY]* | '' )
+       echo 'OK, going ahead.'
+       ;;
+* )
+       echo '
+Aborting dpkg upgrade (you will see error messages from dpkg about this).'
+       exit 1
+       ;;
+esac
+
+if [ -d /usr/lib/dpkg/methods/hd ]
+then
+       echo 'Removing obsolete /usr/lib/dpkg/methods/hd ...'
+       rm -r /usr/lib/dpkg/methods/hd
+fi
+
+exit 0
diff --git a/debian.prerm b/debian.prerm
new file mode 100644 (file)
index 0000000..59a6067
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh -
+
+set -e
+
+cd /usr/bin
+test -f dpkg-deb.dist || ln dpkg-deb dpkg-deb.dist
+
+install-info --quiet --remove /usr/info/Guidelines
+install-info --quiet --remove /usr/info/debian-guidelines
+install-info --quiet --remove /usr/info/guidelines
+install-info --quiet --remove /usr/info/debian-guidelines.info.gz
+install-info --quiet --remove /usr/info/guidelines.info.gz
diff --git a/debian.rules b/debian.rules
new file mode 100755 (executable)
index 0000000..a981e8f
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/make -f
+
+package=dpkg
+version=1.1.4
+
+archi=$(shell dpkg --print-architecture)
+DIR:=$(shell pwd)
+
+build:
+       $(checkdir)
+       ./configure --prefix=/usr
+       $(MAKE)
+       touch build
+
+clean:
+       $(checkdir)
+       -rm -f build
+       -$(MAKE) -i distclean
+       -rm -rf debian-tmp* *~ *.orig ./#*# tmp.*
+       -rm -f config.cache config.status config.h install config.log
+       find -name '*~' -print0 | xargs -r0 rm --
+
+binary:
+#checkroot build
+       -rm -rf debian-tmp
+       mkdir debian-tmp debian-tmp/DEBIAN
+       install -d debian-tmp/usr/doc/{copyright,dpkg}
+       cp debian.preinst debian-tmp/DEBIAN/preinst
+       if file main/dpkg | grep -q ELF; then \
+               if [ $(archi) = i386 ]; then \
+                       sed -e '5s/=/ (>= 5.2.18-2)/' <debian.control >tmp.control ; \
+                       sed -e 's/^# i386elf: //' <debian.preinst \
+                               >debian-tmp/DEBIAN/preinst ; \
+               else \
+                       sed -e '5s/=//' <debian.control >tmp.control ; \
+               fi ; \
+       else \
+               cp debian.controlaout tmp.control ; \
+       fi
+       sed -e '2s/=/$(version)/; 3s/=/$(archi)/' tmp.control >debian-tmp/DEBIAN/control
+       cp debian.prerm debian-tmp/DEBIAN/prerm
+       cp debian.postinst debian-tmp/DEBIAN/postinst
+       chmod +x debian-tmp/DEBIAN/{postinst,prerm,preinst}
+       $(MAKE) prefix=$(DIR)/debian-tmp/usr \
+               datadir=$(DIR)/debian-tmp/var/lib/dpkg \
+               etcdir=$(DIR)/debian-tmp/etc \
+               install
+       gzip -9 debian-tmp/usr/info/guidelines.info*
+       cp debian.README debian-tmp/usr/doc/copyright/dpkg
+       cp TODO debian-tmp/usr/doc/dpkg/WISHLIST
+       touch debian-tmp/var/lib/dpkg/{status,available}
+       chown -R root.root debian-tmp
+       chmod -R g-ws debian-tmp
+       cd debian-tmp && \
+       tar cf ../../$(package)-$(version).nondebbin.tar usr var && \
+       gzip -9vf ../../$(package)-$(version).nondebbin.tar
+       mv debian-tmp/usr/bin/dpkg-deb{,.dist}
+       rm debian-tmp/var/lib/dpkg/{status,available}
+       dpkg --build debian-tmp
+       if file main/dpkg | grep -q ELF; then \
+               mv debian-tmp.deb ../dpkg-$(version)elf.deb ; \
+               mv ../dpkg-$(version).nondebbin.tar.gz \
+                  ../dpkg-$(version)elf.nondebbin.tar.gz ; \
+       else \
+               mv debian-tmp.deb ../dpkg-$(version).deb ; \
+       fi
+
+define checkdir
+       test -f include/dpkg.h
+endef
+
+source:                clean
+       chmod +x debian.rules
+       cd .. && \
+       tar cf $(package)-$(version).tar $(package)-$(version) && \
+       gzip -9vf $(package)-$(version).tar
+diff:
+       @echo '((( no diff - this package is a Debian special )))'
+
+checkroot:
+       $(checkdir)
+       test root = "`whoami`"
+
+.PHONY: binary source diff clean checkroot
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..9b9724c
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+man5dir = $(mandir)/man5
+man5 = 5
+docdir = $(prefix)/doc
+devdocdir = $(docdir)/dpkg
+
+DIST = Makefile.in $(SRC) $(MAN)
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+
+DEVDOCS= auto-deconfiguration.txt dependency-ordering.txt \
+ disappear-replace.txt diversions.text \
+ essential-flag.txt version-ordering.txt
+
+# Files folded into main guidelines document
+OBSOLETEDOCS= descriptions.txt upgrades+errors.txt \
+ maintainer-script-args.txt virtual-dependencies.txt
+
+all:           $(DEVDOCS) guidelines.info
+
+guidelines.info: guidelines.texi
+               $(MAKEINFO) $(srcdir)/guidelines.texi
+
+database-structure.ps: database-structure.fig
+               fig2dev -L ps -c -l _ -P <database-structure.fig >ps
+               mv ps database-structure.ps
+
+database-structure.monops: database-structure.ps
+               perl -pe 's:^/(col[0-7]) \{[01 ]*1[01 ]* setrgbcolor\}\
+ bind def$$:/$$1 {} bind def:' database-structure.ps >ps
+               mv ps database-structure.monops
+
+#dpkg.dvi:
+#              $(TEXI2DVI) $(srcdir)/dpkg.texi
+#
+#dpkg.info:
+#              $(MAKEINFO) $(srcdir)/dpkg.texi
+
+clean:
+               rm -f database-structure.ps database-structure.monops ps
+               rm -f *.{aux,cp,dvi,fn,ky,log,pg,toc,tp,vr}
+               rm -f guidelines.info
+
+distclean:
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
+               $(INSTALL_DATA) deb.5 $(man5dir)/deb.$(man5)
+               $(INSTALL_DATA) deb-control.5 $(man5dir)/deb-control.$(man5)
+               $(INSTALL_DATA) guidelines.info guidelines.info-*[0-9] \
+                       $(infodir)/.
+               set -e; for d in $(DEVDOCS) ; do \
+                       $(INSTALL_DATA) $$d $(devdocdir)/$$d ; \
+               done
diff --git a/doc/auto-deconfiguration.txt b/doc/auto-deconfiguration.txt
new file mode 100644 (file)
index 0000000..5cc0ef5
--- /dev/null
@@ -0,0 +1,62 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Re: dpkg maintainer script calls and arguments
+In-Reply-To: <1506077@toto.iv>
+FCC: ~/mail/Outbound
+--text follows this line--
+In order to support easier upgrades where important packages get split
+into several pieces, I have implemented the following scheme, which I
+described on debian-private a while ago.  It is enabled by the use of
+`--auto-deconfigure', or `-B', and the dselect method scripts in
+0.93.76 have been changed to supply this option.
+
+] I plan to make it possible to `deconfigure' packages at installation
+] time, in order to keep dependency invariants satisfied.  In a sane
+] installation this will mean that everything will work right, even when
+] (for example) an important package is split into two pieces or
+] packages.
+] 
+] Basically, suppose that package A is being split into A1 and A2, and B
+] and C depend on A1 and A2 respectively.  If you try to install A1 dpkg
+] will consider removing A (because of the conflict between A and each
+] of A1 and A2), but then C's dependency is not satisifed, and if you
+] try to install A2 B's dependency wouldn't be satisfied.
+] 
+] At the moment dpkg will simply refuse to do it.  You have to say
+] --force-depends, or remove either B or C.
+] 
+] I'm going to arrange that dpkg will automatically deconfigure B or C,
+] as appropriate, and try to reconfigure it later.
+] 
+] So, if you do `dpkg -i A1.deb A2.deb' all will be well; if you do
+] `dpkg -i A1.deb' you'll get A1 installed and configured correctly, but
+] error messages about C being broken, and in order to fix C you'll have
+] to install A2 as well, or return to A (dpkg will remove A1).
+] 
+] All of this will appear very automatic to people who use dselect.
+] People who do things manually will have a slightly more complicated
+] task, as dpkg won't remove A (in the scenario above) unless it has
+] been selected for deinstallation using dselect or dpkg --remove (which
+] would fail because of the dependencies from B and C).
+
+This means that maintainer scripts can get called in two new ways:
+  <prerm(C)> deconfigure in-favour <A1> <version> removing <A> <v.>
+  <postinst(C)> abort-deconfigure in-favour <A1> <version> removing <A> <v.>
+using the example package names above.
+
+The first call happens before the prerm script of the package which is
+being removed (A) is called; the second happens if an error occurs and
+dpkg wants to back out of the installation.
+
+If the installation of both A1 and A2 is successful dpkg will then
+call both
+  <postinst(B)> configure
+  <postinst(C)> configure
+as usual.
+
+Some time ago I posted a message documenting all the maintainer script
+calls and their arguments.  Below is a revised version of that
+message.  I shall upload it as maintainer-script-args.txt, and it
+should go in project/standards.  The top half of this message will go
+in auto-deconfiguration.txt.
+
+Ian.
diff --git a/doc/database-structure.fig b/doc/database-structure.fig
new file mode 100644 (file)
index 0000000..462e2f6
--- /dev/null
@@ -0,0 +1,487 @@
+#FIG 2.1
+80 2
+6 59 74 199 169
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 129 199 129 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 149 199 149 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 129 69 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        59 109 199 109 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 129 139 169 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        199 169 199 89 59 89 59 169 199 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 89 139 109 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 104 name\ 1
+4 0 12 10 0 -1 0 0.000 4 9 84 64 122 pkginfoperfile\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 74 144 depends\ 1
+4 0 12 10 0 -1 0 0.000 4 9 48 74 162 depended\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 59 84 pkginfo\ 1
+-6
+6 59 394 199 489
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 449 199 449 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 469 199 469 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 449 69 489 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        59 429 199 429 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 449 139 489 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        199 489 199 409 59 409 59 489 199 489 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 409 139 429 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 424 name\ 1
+4 0 12 10 0 -1 0 0.000 4 9 84 64 442 pkginfoperfile\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 74 464 depends\ 1
+4 0 12 10 0 -1 0 0.000 4 9 48 74 482 depended\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 59 404 pkginfo\ 1
+-6
+6 59 234 199 329
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 289 199 289 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 309 199 309 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        69 289 69 329 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        59 269 199 269 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 289 139 329 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        199 329 199 249 59 249 59 329 199 329 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        139 249 139 269 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 264 name\ 1
+4 0 12 10 0 -1 0 0.000 4 9 84 64 282 pkginfoperfile\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 74 304 depends\ 1
+4 0 12 10 0 -1 0 0.000 4 9 48 74 322 depended\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 59 244 pkginfo\ 1
+-6
+6 559 74 699 169
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        569 129 699 129 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        569 149 699 149 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        569 129 569 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        559 109 699 109 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        639 129 639 169 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        699 169 699 89 559 89 559 169 699 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        639 89 639 109 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 564 104 name\ 1
+4 0 12 10 0 -1 0 0.000 4 9 84 564 122 pkginfoperfile\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 574 144 depends\ 1
+4 0 12 10 0 -1 0 0.000 4 9 48 574 162 depended\ 1
+4 0 12 10 0 -1 0 0.000 4 9 42 559 84 pkginfo\ 1
+-6
+6 399 119 499 214
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        499 214 499 134 399 134 399 214 499 214 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        399 154 499 154 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        399 174 499 174 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        399 194 499 194 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        439 134 439 214 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 404 149 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 404 169 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 404 189 list\ 1
+4 0 12 10 0 -1 0 0.000 4 9 24 404 209 type\ 1
+4 0 12 10 0 -1 0 0.000 4 9 60 399 129 dependency\ 1
+-6
+6 654 224 754 319
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        754 319 754 239 654 239 654 319 754 319 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        654 259 754 259 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        654 279 754 279 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        654 299 754 299 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        694 239 694 319 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 659 254 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 659 274 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 659 294 list\ 1
+4 0 12 10 0 -1 0 0.000 4 9 24 659 314 type\ 1
+4 0 12 10 0 -1 0 0.000 4 9 60 654 234 dependency\ 1
+-6
+6 164 294 174 304
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        164 294 174 304 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        164 304 174 294 9999 9999
+-6
+6 164 454 174 464
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        164 454 174 464 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        164 464 174 454 9999 9999
+-6
+6 464 159 474 169
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        464 159 474 169 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        464 169 474 159 9999 9999
+-6
+6 719 264 729 274
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        719 264 729 274 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+        719 274 729 264 9999 9999
+-6
+6 164 154 174 164
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        164 154 174 164 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        164 164 174 154 9999 9999
+-6
+6 354 339 364 349
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        354 339 364 349 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        354 349 364 339 9999 9999
+-6
+6 269 259 389 394
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        269 294 389 294 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        269 314 389 314 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        269 334 389 334 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        269 354 389 354 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        329 274 329 394 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        389 394 389 274 269 274 269 394 389 394 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        269 374 389 374 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 269 269 deppossi\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 274 289 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 274 309 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 274 329 ed\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 274 389 version\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 274 349 nextrev\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 274 369 backrev\ 1
+-6
+6 354 359 364 369
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        354 359 364 369 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        354 369 364 359 9999 9999
+-6
+6 74 564 194 599
+4 0 12 12 0 -1 0 0.000 4 12 84 74 579 Package: foo\ 1
+4 0 12 12 0 -1 0 0.000 4 12 119 74 595 Depends: a | b, c\ 1
+-6
+6 389 449 399 459
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        389 449 399 459 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        389 459 399 449 9999 9999
+-6
+6 389 509 399 519
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        389 509 399 519 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        389 519 399 509 9999 9999
+-6
+6 304 409 424 544
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        304 444 424 444 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        304 464 424 464 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        304 484 424 484 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        304 504 424 504 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        364 424 364 544 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        424 544 424 424 304 424 304 544 424 544 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        304 524 424 524 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 304 419 deppossi\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 309 439 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 309 459 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 309 479 ed\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 309 539 version\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 309 499 nextrev\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 309 519 backrev\ 1
+-6
+6 259 119 359 214
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        359 214 359 134 259 134 259 214 359 214 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        259 154 359 154 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        259 174 359 174 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        259 194 359 194 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        299 134 299 214 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 264 149 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 264 169 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 264 189 list\ 1
+4 0 12 10 0 -1 0 0.000 4 9 24 264 209 type\ 1
+4 0 12 10 0 -1 0 0.000 4 9 60 259 129 dependency\ 1
+-6
+6 479 279 599 414
+6 564 359 574 369
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        564 359 574 369 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        564 369 574 359 9999 9999
+-6
+6 564 319 574 329
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        564 319 574 329 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        564 329 574 319 9999 9999
+-6
+6 479 279 599 414
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        479 314 599 314 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        479 334 599 334 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        479 354 599 354 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        479 374 599 374 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        539 294 539 414 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        599 414 599 294 479 294 479 414 599 414 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        479 394 599 394 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 479 289 deppossi\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 484 309 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 484 329 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 484 349 ed\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 484 409 version\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 484 369 nextrev\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 484 389 backrev\ 1
+-6
+6 564 379 574 389
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        564 379 574 389 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        564 389 574 379 9999 9999
+-6
+1 3 0 1 4 0 0 0 0.000 1 0.000 569 304 5 5 569 304 574 309
+1 3 0 1 6 0 0 0 0.000 1 0.000 569 344 5 5 569 344 574 349
+4 0 0 12 0 -1 0 0.000 4 6 5 589 289 c\ 1
+-6
+6 644 409 764 544
+6 729 489 739 499
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        729 489 739 499 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+        729 499 739 489 9999 9999
+-6
+6 729 449 739 459
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        729 449 739 459 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+        729 459 739 449 9999 9999
+-6
+6 644 409 764 544
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        644 444 764 444 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        644 464 764 464 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        644 484 764 484 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        644 504 764 504 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        704 424 704 544 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+        764 544 764 424 644 424 644 544 764 544 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+        644 524 764 524 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 644 419 deppossi\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 649 439 up\ 1
+4 0 12 10 0 -1 0 0.000 4 7 24 649 459 next\ 1
+4 0 12 10 0 -1 0 0.000 4 7 12 649 479 ed\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 649 539 version\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 649 499 nextrev\ 1
+4 0 12 10 0 -1 0 0.000 4 7 42 649 519 backrev\ 1
+-6
+1 3 0 1 4 0 0 0 0.000 1 0.000 734 434 5 5 734 434 739 439
+1 3 0 1 6 0 0 0 0.000 1 0.000 734 474 5 5 734 474 739 479
+1 3 0 1 5 0 0 0 0.000 1 0.000 734 514 5 5 734 514 739 519
+4 0 0 12 0 -1 0 0.000 4 9 6 744 419 b\ 1
+4 0 12 12 0 7 0 0.000 4 9 28 719 539 >1.0\ 1
+-6
+6 449 564 589 599
+4 0 12 12 0 -1 0 0.000 4 12 70 449 579 Package: c\ 1
+4 0 12 12 0 -1 0 0.000 4 11 140 449 595 Recommends: b (>1.0)\ 1
+-6
+1 3 0 1 1 0 0 0 0.000 1 0.000 169 139 5 5 169 139 174 144
+1 3 0 1 1 0 0 0 0.000 1 0.000 669 139 5 5 669 139 674 144
+1 3 0 1 1 0 0 0 0.000 1 0.000 329 164 5 5 329 164 334 169
+1 3 0 1 2 0 0 0 0.000 1 0.000 329 184 5 5 329 184 334 189
+1 3 0 1 2 0 0 0 0.000 1 0.000 469 184 5 5 469 184 474 189
+1 3 0 1 2 0 0 0 0.000 1 0.000 724 289 5 5 724 289 729 294
+1 3 0 1 5 0 0 0 0.000 1 0.000 169 479 5 5 169 479 174 484
+1 3 0 1 5 0 0 0 0.000 1 0.000 669 159 5 5 669 159 674 164
+1 3 0 1 4 0 0 0 0.000 1 0.000 724 249 5 5 724 249 729 254
+1 3 0 1 4 0 0 0 0.000 1 0.000 329 144 5 5 329 144 334 149
+1 3 0 1 4 0 0 0 0.000 1 0.000 469 144 5 5 469 144 474 149
+1 3 0 1 5 0 0 0 0.000 1 0.000 169 319 5 5 169 319 174 324
+1 3 0 1 2 0 0 0 0.000 1 0.000 359 304 5 5 359 304 364 309
+1 3 0 1 4 0 0 0 0.000 1 0.000 359 284 5 5 359 284 364 289
+1 3 0 1 6 0 0 0 0.000 1 0.000 359 324 5 5 359 324 364 329
+1 3 0 1 5 0 0 0 0.000 1 0.000 394 494 5 5 394 494 399 499
+1 3 0 1 4 0 0 0 0.000 1 0.000 394 434 5 5 394 434 399 439
+1 3 0 1 6 0 0 0 0.000 1 0.000 394 474 5 5 394 474 399 479
+2 1 0 1 5 0 0 0 0.000 7 1 0
+       0 0 1.000 4.000 8.000
+        169 479 299 479 9999 9999
+2 1 0 1 1 0 0 0 0.000 -1 0 1
+       0 0 1.000 4.000 8.000
+        394 164 329 164 9999 9999
+3 2 0 1 1 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        169 139 199 139 219 144 239 149 254 149 9999 9999
+        0.000 -190.000 186.321 138.362 193.821 138.362 203.746 139.584
+        214.444 142.861 223.556 145.139 234.254 148.416 241.590 149.319
+        245.340 149.319 0.000 -190.000
+3 2 0 1 1 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        669 139 704 144 719 154 734 234 9999 9999
+        0.000 -190.000 689.270 140.465 698.020 141.715 708.066 145.553
+        716.306 149.925 728.121 167.798 731.871 187.798 0.000 -190.000
+3 2 0 1 2 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        329 184 319 184 314 184 304 194 304 199 304 259 9999 9999
+        0.000 0.000 323.209 184.000 320.709 184.000 317.861 184.000
+        315.246 183.484 310.477 185.460 305.459 190.476 303.484 195.246
+        304.000 197.861 304.000 209.251 304.000 224.251 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        359 304 389 309 399 339 404 384 404 419 9999 9999
+        0.000 0.000 376.183 303.206 383.683 304.456 396.372 315.299
+        397.434 331.869 401.243 349.210 403.427 373.663 404.332 389.993
+        404.332 398.743 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        469 184 504 189 534 229 549 289 9999 9999
+        0.000 0.000 489.097 184.107 497.847 185.357 515.602 195.870
+        528.871 218.224 538.758 238.997 542.508 253.997 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        724 289 709 299 704 414 9999 9999
+        0.000 0.000 714.657 293.115 710.907 295.615 696.821 320.614
+        695.571 349.364 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        394 494 444 499 569 499 639 499 9999 9999
+        0.000 0.000 422.899 497.321 435.399 498.571 472.526 500.423
+        540.524 499.000 580.960 499.000 598.460 499.000 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        669 159 649 159 634 164 604 204 579 289 9999 9999
+        0.000 0.000 657.478 158.436 652.478 158.436 645.334 159.595
+        637.243 161.663 623.745 171.392 609.302 193.426 596.954 218.053
+        590.704 239.303 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        394 434 414 429 419 424 414 279 364 219 9999 9999
+        0.000 0.000 405.666 432.138 410.666 430.888 415.525 428.137
+        418.291 425.798 433.545 387.100 427.322 313.905 408.621 264.907
+        396.121 249.907 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        569 304 554 234 529 189 504 174 9999 9999
+        0.000 0.000 562.162 263.254 558.412 245.754 549.770 222.731
+        537.823 198.122 525.252 185.125 519.002 181.375 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        359 284 359 249 354 219 9999 9999
+        0.000 0.000 359.497 263.759 359.497 255.009 358.568 243.779
+        357.318 236.279 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        734 434 724 379 724 324 9999 9999
+        0.000 0.000 727.366 402.355 724.866 388.605 723.148 369.549
+        723.148 355.799 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        724 249 719 209 699 174 9999 9999
+        0.000 -190.000 722.530 225.840 721.280 215.840 716.720 202.160
+        711.720 193.410 0.000 -190.000
+3 2 0 1 4 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        329 144 304 144 269 139 219 124 204 124 9999 9999
+        0.000 -190.000 314.537 144.305 308.287 144.305 295.917 143.426
+        276.919 140.743 257.308 136.426 231.067 125.771 216.399 123.618
+        212.649 123.618 0.000 -190.000
+3 2 0 1 5 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        169 319 189 319 229 324 254 329 264 329 9999 9999
+        0.000 0.000 180.574 318.787 185.574 318.787 198.208 319.573
+        219.921 322.527 234.742 324.932 248.152 328.421 255.720 329.170
+        258.220 329.170 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        394 474 339 469 299 469 259 469 234 469 204 469 9999 9999
+        0.000 0.000 362.200 470.679 348.450 469.429 329.874 468.586
+        308.112 469.000 289.888 469.000 268.112 469.000 253.305 469.000
+        239.695 469.000 228.874 469.000 221.374 469.000 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        734 474 659 469 434 484 299 489 204 489 9999 9999
+        0.000 0.000 690.661 470.250 671.911 469.000 607.354 469.001
+        485.316 481.339 403.258 485.594 329.783 488.430 282.765 489.301
+        259.015 489.301 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        569 344 594 339 619 304 634 204 644 174 9999 9999
+        0.000 0.000 583.473 343.015 589.723 341.765 603.620 332.780
+        615.079 313.689 628.219 281.222 628.581 226.603 635.271 198.699
+        637.771 191.199 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+       0 0 1.000 4.000 8.000
+        359 324 294 319 204 309 9999 9999
+        0.000 0.000 321.344 321.293 305.094 320.043 278.591 317.552
+        256.091 315.052 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 0 1
+       0 0 1.000 4.000 8.000
+        429 514 564 519 714 519 734 514 9999 9999
+        0.000 0.000 507.163 517.323 540.913 518.573 598.180 519.633
+        679.471 523.251 717.559 518.562 722.559 517.312 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 0 1
+       0 0 1.000 4.000 8.000
+        204 99 364 109 414 139 469 144 9999 9999
+        0.000 0.000 296.049 97.811 336.049 100.311 377.555 113.214
+        400.605 134.627 423.515 142.106 437.265 143.356 0.000 0.000
+4 0 0 12 0 -1 0 0.000 4 9 15 159 104 foo\ 1
+4 0 0 12 0 -1 0 0.000 4 6 5 479 129 c\ 1
+4 0 0 12 0 -1 0 0.000 4 12 42 309 209 depends\ 1
+4 0 0 12 0 -1 0 0.000 4 12 42 449 209 depends\ 1
+4 0 0 12 0 -1 0 0.000 4 9 6 744 234 b\ 1
+4 0 0 12 0 -1 0 0.000 4 6 18 714 314 rec.\ 1
+4 0 0 12 0 -1 0 0.000 4 6 6 164 264 a\ 1
+4 0 0 12 0 -1 0 0.000 4 9 6 164 424 b\ 1
+4 0 0 12 0 -1 0 0.000 4 6 5 664 104 c\ 1
+4 0 0 18 0 -1 0 0.000 4 17 632 64 54 example of the structures (in the C code) which contain related packages information\ 1
+4 0 12 12 0 -1 0 0.000 4 12 70 284 589 Package: a\ 1
+4 0 0 12 0 -1 0 0.000 4 6 6 374 269 a\ 1
+4 0 0 12 0 -1 0 0.000 4 9 6 384 419 b\ 1
+4 0 0 12 0 -1 0 0.000 4 9 15 339 129 a|b\ 1
+4 0 12 12 0 -1 0 0.000 4 12 70 674 589 Package: b\ 1
diff --git a/doc/deb-control.5 b/doc/deb-control.5
new file mode 100644 (file)
index 0000000..9436641
--- /dev/null
@@ -0,0 +1,104 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Author: Raul Miller
+.\" Includes text from the debian Guidelines by Ian Jackson, Ian Murdock
+.TH DEB-CONTROL 5 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+deb\-control \- Debian GNU/Linux packages' master control file format
+.SH SYNOPSIS
+control
+.SH DESCRIPTION
+Master control file format:
+.LP
+The `control' file contains a number of fields.  Each field begins
+with a tag, such as `PACKAGE' or `VERSION' (case insensitive),
+followed by a colon, and the body of the field. Fields are delimited
+only by field tags.  In other words, field text may be multiple lines
+in length, but the installation tools will generally join lines when
+processing the body of the field.
+.SH REQUIRED FIELDS
+.TP
+.BR PACKAGE: \ <Short\ name\ of\ package>
+The value of this field is used to generate file names by some
+installation tools.
+.TP
+.BR VERSION: \ <Original\ version\ number>
+typically, this is the original portable package's version
+number in whatever form the program's author uses.
+.TP
+.BR PACKAGE_REVISION: \ <Debian\ package\ revision\ number>
+this should usually be a plain number, or perhaps two numbers
+separated by a full stop.
+.TP
+.BR MAINTAINER: \ <Name\ and\ e-mail\ address\ of\ package\ maintainer>
+should be in the format  Joe Bloggs <jbloggs@foo.com>.
+.TP
+.BR DESCRIPTION: \ <Description\ of\ package> 
+.SH OPTIONAL FIELDS
+.TP
+.BR DEPENDS: \ <Short\ names\ of\ prerequisite\ packages>
+list of packages that are required for this package to provide a
+non-trivial amount of functionality.  The package maintenance software
+will not allow a package to be installed without also installing
+packages listed in its 
+.B DEPENDS
+field, and will rin the postinst scripts of packages listed in DEPENDS
+fields before those of the packages which depend on them, and run
+prerm scripts before.
+.TP
+.BR RECOMMENDED: \ <Short\ names\ of\ related,\ recommended\ packages>
+lists packages that would be found together with
+this one in all but unusual installations.  The package maintenance
+software will warn the user if they install a package without those
+listed in its
+.B RECOMMENDED
+field.
+.LP
+The syntax of
+.B DEPENDS
+and
+.B RECOMMENDED
+is a list of groups of alternative packages.  Each group is a list of
+packages separated by vertical bar (or `pipe') symbols, `|'.  The
+groups are separated by commas.  Each package is a package name
+optionally followed by a version number specification in parentheses.
+A version number may start with a `>', in which case any later version
+will match, and may specify or omit the Debian packaging revision
+(separated by a hyphen).  Commas are to be read as `AND', and pipes as
+`OR', with pipes binding more tightly.
+.TP
+.BR OPTIONAL: \ <Short\ names\ of\ related,\ optional\ packages>
+lists packages that are related to this one and can perhaps enhance
+its usefulness, but without which installing this package is perfectly
+reasonable.  The package maintenance software will not moan at the
+user for not selecting
+.B OPTIONAL
+related packages, but may use the information in the
+.B OPTIONAL
+field to assist the user during package selection.
+.TP
+.BR CONFLICTS: \ <Short\ names\ of\ packages\ which\ conflict\ with\ this\ one>
+lists packages that conflict with this one, for example by containing
+files with the same names (an example would be Smail vs. Sendmail).
+The package maintenance software will not allow conflicting packages
+to be installed.  Two conflicting packages should each include a
+.B CONFLICTS
+line mentioning the other.
+.LP
+The syntax of
+.B OPTIONAL
+and
+.B CONFLICTS
+is a list of package names, separated by commas (and optional
+whitespace).  In the
+.B CONFLICTS
+field, the comma should be read as `OR'.
+
+.SH BUGS
+This manpage is seriously out of date.
+
+.SH SEE ALSO
+.BR deb (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dpkg-dep (8),
+.BR dselect (8).
diff --git a/doc/deb.5 b/doc/deb.5
new file mode 100644 (file)
index 0000000..35070eb
--- /dev/null
+++ b/doc/deb.5
@@ -0,0 +1,69 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Author: Raul Miller
+.TH DEB 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME 
+deb - Debian GNU/Linux package format
+.SH SYNOPSIS
+.IB <packagename>.deb
+.SH DESCRIPTION
+Debian archive file format.
+Version 0.93 is implemented as follows:
+.TP
+line 1:
+version number 
+.RB ( 0.93 ...),
+followed by
+.BR newline .
+.TP
+line 2:
+number of characters occupied by control area expressed in decimal,
+followed by 
+.BR newline .
+.TP 
+control area:
+compressed gzipped ustar formatted archive.  Must contain file named
+.BR control .
+May optionally contain files named:
+.BR conffiles ,
+.BR preinst ,
+.BR prerm ,
+.BR postint ,
+.BR postrm .
+.TP 
+files archive area:
+compressed gzipped ustar formatted archive.  [with file structures
+designed to be unpacked in the root directory].
+.SH FILES
+The files represented in the control area have special significance:
+.TP
+.B control
+see 
+.BR deb-control (5).
+.TP
+.B conffiles
+a line delimited list of "configuration files" which have special
+significance to 
+.BR dpkg (8).
+.TP
+.B preinst
+an executable to be run before unpacking the archived files.
+.TP
+.B prerm
+an executable to be run before removing files from a prior installation.
+.TP
+.B postinst
+an executable to be run after unpacking the archived files.
+.TP
+.B postrm
+an executable to be run after removing files from a prior
+installation.
+
+.BUGS
+There is a new package format, which is not documented here.
+
+.SH SEE ALSO
+.BR deb-control (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dpkg-dep (8),
+.BR dselect (8).
diff --git a/doc/dependency-ordering.txt b/doc/dependency-ordering.txt
new file mode 100644 (file)
index 0000000..f3f6794
--- /dev/null
@@ -0,0 +1,97 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Note about the default for virtal package dependencies
+
+As I wrote some time ago (see below), ordering is significant in the
+Depends and Recommended fields - in the absence of other information
+dselect will suggest to the user that they select the first named
+package in a list of options.
+
+However, there is no way to specify the `order' of several packages
+which all Provide the same thing, when that thing is listed as a
+Dependency.
+
+Eg, if we have:
+ Package: glibcdoc
+ Recommended: info-browser
+
+ Package: info
+ Provides: info-browser
+
+ Package: emacs
+ Provides: info-browser
+
+then (if emacs and info are both in the same Class) dselect's choice
+will be essentially random.
+
+It is important to think about this problem, and to consider whether
+to list one the the packages explicitly.
+
+For example,
+ Package: glibcdoc
+ Recommended: info | info-browser
+
+will do the same as the above, except that it will ensure that `info'
+is the package which dselect will suggest to the user they also select
+if the user has neither it nor Emacs and asks to select glibcdoc.
+
+This is not necessary if one of the packages has a more fundamental
+Class - see the details below.
+
+Ian.
+
+------- Start of forwarded message -------
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Ordering is significant in Depends: and Recommends:
+
+For dselect, the ordering of alternative packages in a Depends: or
+Recommended: line is significant.
+
+When an unsatisfied dependency (Depends or Recommended) or a conflict
+is detected dselect will go into a `recursive package list', where the
+user gets to choose how to resolve the problem.
+
+Usually dselect will suggest to the user that they select the package
+with the most `fundamental' class (eg, it will prefer Base packages to
+Optional ones), or the one that they `most wanted' to select in some
+sense.
+
+However, in the absence of other information dselect will prefer
+packages listed earlier in the unsatisfied entry in the Depends or
+Recommended field.
+
+NB: this doesn't apply to constructions of the form:
+ Package: auctex
+ Depends: emacs, tex
+which specifies that auctex depends on *both* emacs and tex.  In this
+case dselect will suggest to the user that they select both packages.
+
+It applies to constructions of the form:
+ Package: a2gs
+ Recommended: gs_x | gs_both | gs_svga
+Here, dselect will prefer gs_x because it is listed earlier.  (In the
+future I may make it more clever - it may be able to notice, to
+continue the example, that the dependencies of gs_x are not yet
+satisfied while those of gs_svga, are, and thus prefer the latter, or
+in a different situation to notice that gs_both has extra dependencies
+which are satisfied, and thus prefer it to gs_x and gs_svga.  More
+thought is needed in this area.)
+
+One final example.  In the more complicated construction:
+ Package: trn
+ Depends: smail | sendmail, inn | inewsinn
+dselect will prefer smail because it is a Standard package, and
+Sendmail is only Optional, and will prefer inewsinn because it is
+Recommended and inn is only Optional.  So, the default (if none of the
+other packages were selected) would be to select smail and inewsinn.
+
+However, if inewsinn were moved to Optional this would change, and inn
+would be preferred whenever the issue arose after the change.
+
+Optional fields have the same structure as Depends and Recommended
+fields, but they will not arrange for the packages they list to be
+suggested for selection, though they will be offered to the user.
+
+Ian M: can this go in an appendix to the Guidelines ?
+
+Ian.
+------- End of forwarded message -------
diff --git a/doc/descriptions.txt b/doc/descriptions.txt
new file mode 100644 (file)
index 0000000..fdc302b
--- /dev/null
@@ -0,0 +1,112 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Package maintainers please look at your Description fields.
+
+dselect will be much more useful when more packages are more
+informative in the Description they provide in their control file.
+
+So, when you next release a package, could you please check whether
+the `control' file has a good description of the package, formatted as
+described below ?
+
+A small amount of effort here on the part of package maintainers will
+improve the looks of things quite a bit, I think.
+
+BTW, a number of packages have been indenting continuation lines in
+their Description fields thus:
+  Description: gnomovision
+         Gnomovision is ....
+         further blurb ...
+Please don't do this.  According to the scheme described below (which
+I've now implemented), dselect interprets the extra indentation to
+mean `preformatted' text, and doesn't wordwrap it.
+
+Ian.
+
+
+The format of the Description field is as follows:
+
+Description: <single line synopsis>
+ <extended description over several lines>
+
+The extended description has several kinds of line:
+
+ - those starting with a single space are part of a paragraph.
+Successive lines of this form will be word-wrapped when displayed.
+The leading space will usually be stripped off.
+
+ - those starting with two or more spaces.  These will be displayed
+verbatim.  If the display cannot be panned horizontally the displaying
+program will linewrap them `hard' (ie, without taking account of word
+breaks).  If it can they will be allowed to trail off to the right.
+None, one or two initial spaces may be deleted, but the number of
+spaces deleted from each line will be the same (so that you can have
+indenting work right, for example).
+
+ - those containing a single space followed by a single full stop
+character.  These are rendered as blank lines.  This is the ONLY way
+to get a blank line - see below.
+
+ - those containing a space, a full stop and some more characters.
+These are for future expansion.  Don't use them.
+
+IMPORTANT and not so important TIPS:
+
+* ALWAYS START EXTENDED DESCRIPTION LINES WITH AT LEAST ONE WHITESPACE
+CHARACTER.  Fields in the control file and in the Packages file are
+separated by field names starting in the first column, just as in
+RFC822.  Forgetting the whitespace will cause dpkg-deb (>=0.93.23) to
+produce a syntax error when trying to build the package.  If you force
+it to build anyway dpkg will refuse to install the resulting mess.
+
+* DO NOT INCLUDE ANY COMPLETELY EMPTY LINES.  These separate different
+records in the Packages file, and are forbidden in control files.  See
+the previous paragraph for what happens if you get this wrong.
+
+* The single line synopsis should be kept brief - certainly under 80
+characters.  My current working half-dselect displays the first 49
+characters if you're using an 80-column terminal.
+
+* Don't include the package name in the synopsis line.  The display
+software knows how to display this already, and you don't need to
+state it.
+
+* The extended description should describe what the package does, and
+what component it forms of any larger subsystem of which it is a part.
+
+* Put important information first, both in the synopis and extended
+description.  Sometimes only the first part of the synopsis or of the
+description will be displayed.  You can assume that there will usually
+be a way to see the whole extended description.
+
+* You may include information about dependencies and so forth in the
+extended description, if you wish.
+
+* Don't use tab characters.  Their effect is not predictable.
+
+Example control file for Smail:
+
+Package: smail
+Version: 3.1.29.1
+Package_Revision: 8
+Maintainer: Ian Jackson <iwj10@cus.cam.ac.uk>
+Recommended: pine | elm | emacs | mh | mailx
+Optional: metamail
+Depends: cron
+Conflicts: sendmail
+Description: Electronic mail transport system.
+ Smail is the recommended mail transport agent (MTA) for Debian.
+ .
+ An MTA is the innards of the mail system - it takes messages from
+ user-friendly mailer programs and arranges for them to be delivered
+ locally or passed on to other systems as required.
+ .
+ In order to make use of it you must have one or more user level
+ mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+ and VM as mailreaders) installed.  If you wish to send messages other
+ than just to other users of your system you must also have appropriate
+ networking support, in the form of IP or UUCP.
+
+-- 
+Ian Jackson, at home.         ijackson@nyx.cs.du.edu or iwj10@cus.cam.ac.uk
++44 1223 575512    Escoerea on IRC.   http://www.cl.cam.ac.uk/users/iwj10/
+2 Lexington Close, Cambridge, CB4 3LS, England.   Urgent: iwj@cam-orl.co.uk
diff --git a/doc/disappear-replace.txt b/doc/disappear-replace.txt
new file mode 100644 (file)
index 0000000..8335a0e
--- /dev/null
@@ -0,0 +1,44 @@
+From ian Tue Apr 18 23:30:04 1995 
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+       [nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+       nil)
+X-VM-Summary-Format: "%3n %a %2d %3m  %-19.19F  %s\n"
+X-VM-Labels: nil
+X-VM-VHeader: ("Resent-" "From:" "Sender:" "To:" "Apparently-To:" "Cc:" "Subject:" "Date:") nil
+X-VM-Bookmark: 5
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Handling of base packages
+
+I propose to implement the following scheme to enable obsolete base
+packages to disappear, and to allow files in the base packages to move
+between one package and another.
+
+1. When a package is installed, and contains files that are already
+marked as belonging to some other package, the older package will have
+the files that have been overwritten removed from its file list.
+
+2. When a package ceases to contain any files due to the action of
+point 1 above, its postrm script is run with the argument `disappear'
+(in place of `remove', `purge' or whatever).  It will then be moved
+into the `purge ok not-installed' state, so that it will cease to
+appear in dpkg and dselect lists.  Its conffiles will be ignored,
+*not* purged.  The prerm will *not* be run as the packaging system
+doesn't know what files are in a package until it unpacks it.
+
+This will all happen during the `unpack' phase of the replacing
+package.
+
+3. If a base system package which is being installed conflicts with
+another base system package which is currently installed on the
+system, the currently installed one will be removed first (the prerm
+will be run with `replace <package> <version>' as arguments, then the
+package will be removed, then the postrm will be run, likewise with
+`replace').  If the replacement fails the removal will be aborted,
+involving running the old packages' scripts with `abort-replace'.
+
+4. Base system packages may not be removed except under 2. or 3.
+above.  (There will be a --force-remove-base flag to allow foolhardy
+users to go ahead anyway.)
+
+Ian.
+
diff --git a/doc/diversions.text b/doc/diversions.text
new file mode 100644 (file)
index 0000000..8cfec09
--- /dev/null
@@ -0,0 +1,131 @@
+(These messages have been edited to conform to the terminology
+eventually decided on.)
+
+------- start of digest (2 messages) (RFC 934 encapsulation) -------
+Resent-Message-Id: <m0tcceI-0002c6C@chiark.chu.cam.ac.uk>
+Resent-From: ijackson (Ian Jackson)
+Resent-To: ian
+From: ian@chiark.chu.cam.ac.uk (Ian Jackson)
+To: Debian developers list <debian-devel@pixar.com>
+Subject: `diverting' dpkg for a particular file
+Date: Wed, 17 Jan 96 18:31 GMT
+
+I'm almost finished with the implementation of a feature for dpkg that
+will allow the sysadmin or package maintainer to prevent dpkg from
+overwriting a particular file.
+
+Instead, whenever dpkg finds a package containing that file it
+`redirects' the reference to an alternative name.
+
+Eg, if you were to `divert' /usr/sbin/smail to /usr/sbin/smail.real
+then any package containing /usr/sbin/smail would have the file placed
+as /usr/sbin/smail.real instead.  The feature will work during package
+removal, as well.
+
+There's provision for a single package to be named which is allowed to
+provide a version of the file which will installed under the original
+name.
+
+This feature shouldn't be mixed with the conffiles update mechanism,
+as this is unlikely to produce useful results and likely to produce
+confusion on the part of the user at the very least and possibly on
+the part of dpkg too :-).
+
+No package should contain a file whose name is the diverted name of
+another file; dpkg will spot this and balk if such a package is
+installed when the diversion is in place, or if a diversion is set up
+which involves overwriting an existing file whether managed by dpkg
+or not (this latter check only happens if dpkg-divert is given the
+--rename option which makes it actually rename any copy of the file
+found in the filesystem).
+
+Only one diversion for a particular file is allowed, and you can't
+divert A to B and then B to C.
+
+[...]
+
+This feature is intended to be used sparingly; a system administrator
+can use it to keep a locally-installed version of a piece of system
+software that has to live in a particular place.
+
+A package should preferably only use it if the package's main function
+is to replace the file in question (whether or not the diverted - ie,
+replaced, in this case - version of the file needs to be available);
+otherwise a sysadmin might find that the feature wasn't available to
+them when they wanted to install their own version of the file because
+a package had already done so.
+
+It's possible that I might introduce a facility that would allow
+*requests* for redirection of files to be redirected themselves, by
+using a special 2nd-level redirection option.
+
+Ian.
+------------------------------
+To: debian-devel@Pixar.com
+Subject: Re: `overriding' dpkg for a particular file
+
+[...]
+Forgive me for being perhaps rather baseic, but here are two examples,
+diagrammatically:
+
+1. Administrator wants to replace a Debian-provided program with
+   their own version, or wants to put a wrapper around it:
+                                            ____________________
+     smail.deb___________                  /                    \
+     |  ...              |                |\____________________/|
+     | /usr/sbin/smail --+----.           |                      |
+     |  ...              |     \          | /                    |
+     |___________________|      \         | /usr                 |
+                                 \        | /usr/sbin            |
+                                  `-------> /usr/sbin/smail.real |
+                                  .-------> /usr/sbin/smail      |
+      ~/stuff/smail/wrapper.c    /        |                      |
+      ~/stuff/smail/wrapper ----'          \____________________/
+
+     # dpkg-divert --divert /usr/sbin/smail.real /usr/sbin/smail
+     # cp ~fred/stuff/smail/wrapper /usr/sbin/smail
+
+2. Package maintainer wants to provide an `improved' version of a
+   file in another package.
+
+     fileutils.deb_______                   ____________________
+     |  ...              |                 /                    \
+     | /bin/ls ----------+----.           |\____________________/|
+     |  ...              |     \          |                      |
+     |___________________|      \         | /                    |
+                                 \        | /bin                 |
+     colour-ls.deb_______         `-------> /bin/ls.mono         |
+     |  ...              |       .--------> /bin/ls              |
+     | /bin/ls ----------+------'         |                      |
+     |  ...              |                 \____________________/
+     |...................|
+     |preinst:           |
+     | dpkg-divert --divert /bin/ls.mono \
+     |   --package colour-ls /bin/ls
+     |...................|
+     |postrm:            |
+     | dpkg-divert --remove --divert /bin/ls.mono \
+     |   --package colour-ls /bin/ls
+     |___________________|
+
+We need a name that applies to `/usr/sbin/smail.real' and
+`/bin/ls.mono', the filenames, in both situations, and another name
+to apply to `/usr/sbin/smail' and `/bin/ls'.
+
+Raul Miller writes ("Re: `overriding' dpkg for a particular file"):
+[...]
+> Also, it would be nice to see either some documentation or some sort
+> of warning about the case where the file is a directory.
+
+If the file is a directory there will be no good effect.  This is
+because the redirection would affect only the entry for the directory
+itself in the packages whose instances if it were being redirected,
+and would not affect any of the files in it.
+
+The most likely result is that dpkg will fail to install the package
+because one of the directories where it has files doesn't exist.  It
+would probably create the `diverted' name of the directory, fail, and
+then clean it up.
+
+Ian.
+------- end -------
diff --git a/doc/dpkg.texi b/doc/dpkg.texi
new file mode 100644 (file)
index 0000000..b9530d6
--- /dev/null
@@ -0,0 +1,101 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename dpkg.info
+@settitle The @code{dpkg} Package Maintenance System
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* dpkg: (dpkg).          The @code{dpkg} package maintenance system.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@setchapternewpage off
+
+@ifinfo
+This file documents the @code{dpkg} package maintenance system.
+
+Copyright (C) 1994 Ian A. Murdock
+
+Permission is granted to make and distribute verbatim copies of this
+document provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one, except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this document
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by The Debian Linux Association.
+@end ifinfo
+
+@titlepage
+@title The @code{dpkg} Package Maintenance System
+@author Ian A. Murdock
+@page
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1994 Ian A. Murdock
+
+Permission is granted to make and distribute verbatim copies of this
+document provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this document
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by The Debian Linux Association.
+@end titlepage
+
+@node Top, Overview, (dir), (dir)
+
+@top Introduction
+@menu
+* Overview::            An overview of the @code{dpkg} package
+                        maintenance system.
+* Installation::        How to install a package with @code{dpkg}.
+* Removal::             How to remove a package with @code{dpkg}.
+* Information::         How to obtain information about both
+                        installed and not-yet-installed packages.
+* Extension::           How to extend @code{dpkg} to support new
+                        package formats.
+* Guidelines::          Guidelines for creating and maintaining
+                        packages for Debian GNU/Linux.
+@end menu
+
+@node Overview
+@chapter Overview
+
+@node Installation
+@chapter Package Installation
+
+@node Removal
+@chapter Package Removal
+
+@node Information
+@chapter Package Information
+
+@node Guidelines
+@chapter Debian GNU/Linux Guidelines
+
+@node Extension
+@chapter How to Extend @code{dpkg} to Support New Package Formats
+
+@bye
diff --git a/doc/essential-flag.txt b/doc/essential-flag.txt
new file mode 100644 (file)
index 0000000..34e8211
--- /dev/null
@@ -0,0 +1,43 @@
+From ian Thu Jul  6 21:14:08 +0100 1995
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+       [nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+       nil)
+In-Reply-To: <m0sTw2a-00063aC@mongo.pixar.com>
+References: <m0sTw2a-00063aC@mongo.pixar.com>
+To: debian-devel@pixar.com
+Subject: Re: non-uninstallable packages
+
+Bruce Perens writes ("non-uninstallable packages"):
+> Assume that a package, such as one in the base, is supposed to be
+> non-uninstallable because it is a critical system component. We should
+> specify that in an unambiguous form, rather than indicating it by
+> specifying "Class: base" in the control file.
+> 
+> I suggest yet another control file field, called "Flags: ". This is
+> followed by a comma-delimited set of flags. An example might be:
+>      Flags: no-uninstall
+> 
+> Another alternative would be to add control-file fields for each flag.
+> In this case, the field would appear as:
+>      Allow-uninstall: no
+> ...and the default would be "yes".
+
+I think you're right.  Bill spotted that we were trying to overload
+the `Class' field.
+
+I don't think there's any need for a generic `Flags:' field; a simple
+extra field is fine, unless we're going to have an awful lot of
+boolean flags applying to packages (any attribute with a value is
+better handled using a field of its own anyway).
+
+I propose to call the new field `Essential', with allowable values
+`yes' and `no' and a default of `no'.
+
+This will be clearer all round, I think, than attempting to describe
+dpkg behaviour in the field name.
+
+If I don't have to make an emergency bugfix release of dpkg first this
+will be in the next version.  I'll modify dselect too.
+
+Ian.
+
diff --git a/doc/guidelines.info-1 b/doc/guidelines.info-1
new file mode 100644 (file)
index 0000000..ac91714
--- /dev/null
@@ -0,0 +1,1039 @@
+This is Info file guidelines.info, produced by Makeinfo-1.63 from the
+input file ./guidelines.texi.
+
+START-INFO-DIR-ENTRY
+* Guidelines: (guidelines).       How to make Debian packages.
+END-INFO-DIR-ENTRY
+
+\1f
+File: guidelines.info,  Node: Top,  Next: Additional Information,  Prev: (dir),  Up: (dir)
+
+Debian GNU/Linux Packaging Guidelines
+*************************************
+
+   This file documents the steps that must be taken in the preparation
+of a Debian GNU/Linux package.  All submissions to be included in the
+distribution proper and all packages to be considered for `contrib' or
+`non-free' availability *must* conform to the guidelines and standards
+described in this document or they cannot be included or made available
+at the archive with the distribution.
+
+   Please read the Guidelines carefully.  If you have comments or
+questions, please contact `debian-devel@pixar.com'.  If you are
+planning on going further than just contributing a package (i.e., if
+you plan to maintain it for an extended period of time or if you are
+generally interested in becoming more involved in the Project), you
+should join the `debian-devel' mailing list.  For more details, read
+`info/mailing-lists.txt', available at any Debian GNU/Linux archive.
+
+   (This file was last updated on 26th January 1996.  Please check the
+most recent `dpkg' package at any Debian GNU/Linux archive for a
+potentially more up to date copy.)
+
+* Menu:
+
+* Additional Information::      Where other info is to be found.
+* Package Copyright::           A few words about the importance of
+                                understanding the package copyright.
+* Package Content::             Requirements for the package content.
+* Source Package::              Creating the source package.
+* Binary Package::              Creating the binary package.
+* Control Files::               The binary package control files.
+* Appendix::                    More specific details about some aspects.
+
+\1f
+File: guidelines.info,  Node: Additional Information,  Next: Package Copyright,  Prev: Top,  Up: Top
+
+Additional Information
+**********************
+
+   These Guidelines are intended to be fairly general.  More specific
+information is available about certain aspects of building packages,
+such as how to use the features of Init under Debian GNU/Linux and how
+to interact with some more technical details of dpkg's operation.  This
+information can be found in the directory `doc/package-developer' at
+any Debian GNU/Linux archive.  At the time of this writing, the
+following documents are available:
+
+`virtual-package-names-list.text'
+     The list of virtual package names currently in use, together with
+     the procedure for getting new virtual package names allocated.
+
+`auto-deconfiguration.txt'
+     How dpkg can sometimes automatically deconfigure packages in order
+     to do bulk installations smoothly.
+
+`dpkg-essential-flag.txt'
+     How to tell dpkg a package is essential and should not be removed.
+     (This is for the use of base system packages only.)
+
+`dpkg-disappear-replace.txt'
+     What happens when a package appears to have been completely
+     replaced.
+
+   In the future, we hope also to make available:
+
+`copyright.txt'
+     How to choose a good copyright notice to attach to new programs.
+
+`version-ordering.txt'
+     The algorithm with which packages' version numbers are compared.
+
+   Also, you should download the sample files and the sample package
+(GNU Hello) available in `standards/samples'.  You may use any of this
+material as a starting point for new packages.  The following sample
+files, incidentally, are available:
+
+   * debian.README
+
+   * debian.control
+
+   * debian.postinst
+
+   * debian.postrm
+
+   * debian.rules
+
+   Some more detailed information about certain topics is available in
+the appendix to this document (*note Appendix::.).
+
+\1f
+File: guidelines.info,  Node: Package Copyright,  Next: Package Content,  Prev: Additional Information,  Up: Top
+
+Package Copyright
+*****************
+
+   Please study the copyright of your submission *carefully* and
+*understand it* before proceeding!  If you have doubts or questions,
+please ask!
+
+   In order to understand how we classify and distribute certain
+packages, it is important to understand the distinction between being
+freely available and being freely redistributable.
+
+   Being "freely available", quite simply, means that the software can
+be made available freely, at least for non-commercial purposes and in
+its original, unmodified form.  This includes packages made available
+freely that have restrictions on non-commercial use, redistribution of
+modifications, etc.  Being freely available, therefore, has nothing to
+do with being able to modify and redistribute the software.  It only
+means that you can get a copy of the software without having to pay
+(and it does not necessarily mean that you can *use* the software
+without having to pay--shareware is an example of freely available
+software).
+
+   "freely redistributable", while generally being freely available,
+goes beyond just being freely available.  Freely redistributable means
+that that the software, in addition to being able to be made available
+freely, must be able to be freely modified and redistributed without
+restriction.
+
+   All submissions to be included in the distribution proper *must* be
+freely redistributable.
+
+   In addition to the distribution, the Project maintains two separate
+archives of software packages with the distribution: the `contrib'
+archive and the `non-free' archive.
+
+   `contrib' is an archive of user-contributed packages that are not
+maintained by the Project, packages that were once maintained by the
+Project but that are no longer actively maintained, and packages that
+are maintained by the Project but that are not yet considered ready for
+inclusion in the distribution proper (i.e., ALPHA and BETA packages).
+As above, all submissions for inclusion in the `contrib' archive *must*
+be freely redistributable.
+
+   `non-free' is an archive of packages with either restrictive or
+unclear terms of copying or modification.  If a package has *any*
+restrictions on modification or redistribution, it can not be included
+in the distribution or `contrib' archive.  It can only be included in
+the `non-free' archive, and then only if it is freely available.
+
+   In summary, in order to be included in the distribution proper or the
+`contrib' archive, a package must be *freely redistributable*.  Anyone
+must be able to make copies of it, modify it, redistribute it with
+their modifications in place, include it on a CD-ROM, or generally sell
+it.  To be included in the `non-free' archive, a package may have
+restrictions, as long as the package remains *freely available*.  We
+must be available to make it available freely at the archive, and anyone
+must be able to make copies of it and use it for at least
+non-commercial, personal purposes.  Software that will typically be
+included in `non-free' are software that does not allow commercial
+distribution, software that does not allow modification or
+redistribution of modifications, commercial "demos", and "shareware".
+
+   When in doubt, send mail to `iwj10@cus.cam.ac.uk' and
+`imurdock@debian.org'.  Be prepared to provide us with the copyright
+statement.  Software covered by the GPL, public domain software and
+BSD-like copyrights are safe; be wary of the phrases "commercial use
+prohibited" and "distribution restricted".
+
+   Every package submission *must* be accompanied by verbatim copy of
+its copyright (with the exceptions of public domain packages and those
+covered by the UCB BSD licence or the GNU GPL or LGPL; in these cases
+simply indicate which is appropriate).  This information must be
+included in a file installed to the directory `/usr/doc/copyright'.
+See below for details.
+
+\1f
+File: guidelines.info,  Node: Package Content,  Next: Source Package,  Prev: Package Copyright,  Up: Top
+
+Package Content
+***************
+
+   The following requirements apply equally to both the binary and
+source packages.  In either case, when files have been installed, they
+must conform to the requirements described in this section.
+
+   The primary rule in Debian GNU/Linux is to follow the Linux "File
+System Standard" ("FSSTND").  The location of installed files *must*
+comply *fully* with the FSSTND.  The latest version of this document
+can be found alongside the Guidelines or at `tsx-11.mit.edu' in
+`/pub/linux/docs/linux-standards/fsstnd'.  Specific questions about
+following the standard should be addressed to Daniel Quinlan, the
+FSSTND coordinator, at `quinlan@yggdrasil.com'.
+
+   In addition to the FSSTND, all Debian GNU/Linux packages must follow
+the guidelines below.
+
+   * Directories should be mode 755 or (for group-writability) mode
+     2775, with the exception of special "system" directories that need
+     to be another mode.  The ownership of the directory should be
+     consistent with its mode--if a directory is mode 2775, it should
+     be owned by the group that needs write access to it, of course.
+     Use common sense in assigning permissions and ownerships to
+     directories, and make sure that what is done is secure if it is
+     "non-standard".
+
+   * Normal binaries should be mode 755 and owned by `root.root'.  If
+     there is a good reason to use a different mode or ownership, you
+     may do so, but you must try to be as consistent as possible with
+     the rest of the system.  If you need to use a different mode or
+     ownership, please discuss it with `imurdock@debian.org'.
+
+   * Setuid binaries should normally be mode 4755 (not 4711!) and, of
+     course, owned by the appropriate user.
+
+   * Setgid binaries should normally be mode 2755 (not 2711!) and, of
+     course, owned by the appropriate group.
+
+   * Library files should generally be mode 644 and owned by
+     `root.root'.  If the package requires different permissions or
+     ownerships to function correctly, they should be used instead.
+
+   * Manual pages should be mode 644 and owned by `root.root'.  The
+     `nroff' source must be installed.  You should *not* install a
+     preformatted "cat page", and you should only use sections 1 to
+     9--see the FSSTND for more details.  If no manual page is
+     available for a particular program, utility or function and this
+     is reported as a bug on debian-bugs, a symbolic link from the
+     requested manual page to the `undocumented'(7) manual page should
+     be provided. This symbolic link can be created from `debian.rules'
+     like this:
+
+          ln -s ../man7/undocumented.7 debian-tmp/usr/man/man[1-9]/the_requested_manpage.[1-9]
+
+     Do not close the bug report until a proper manpage is available.
+     You may forward the complaint to the upstream maintainers, and
+     mark the bug as forwarded in the Debian bug tracking system.  The
+     GNU Project do not in general consider the lack of a manpage to be
+     a bug, but we do - if they tell you to go away leave the bug open
+     anyway.
+
+   * Info documents should be mode 644, owned by `root.root', and
+     compressed with `gzip -9' when installed.  The package must call
+     `install-info' to update the Info `dir' file.  This should be done
+     in the post-installation script (`postinst'), like this:
+
+          install-info --quiet /usr/info/foobar.info
+
+     The entries should be removed by the pre-removal script (`prerm'),
+     like this:
+
+          install-info --quiet --remove /usr/info/foobar.info
+
+     It is also a good idea to specify a section for the Info `dir'
+     entry.  This is done with the `--section' switch.  To determine
+     which section to use, you should use look at `/usr/info/dir' on
+     your system and choose the most relevant (or create a new section
+     if none of the current sections are relevant).
+
+     If `install-info' cannot find a description entry in the Info file
+     you will have to supply one.  See `install-info'(8) for details.
+
+   * If a package contains any shared libraries you will have to invoke
+     `ldconfig' in both the `postinst' and `prerm' scripts to correctly
+     update the library links.  See `ldconfig'(8) for details.
+
+   * Any additional documentation that comes with the package can be
+     installed at the discretion of the package maintainer.  Text
+     documentation should be mode 644, owned by `root.root', installed
+     to `/usr/doc', and compressed with `gzip -9' unless it is small.
+
+     If a subdirectory of `/usr/doc' is warranted, please do create one.
+     Please do not install DVI, PostScript, or large textual
+     documentation in the same package; upload such documentation as a
+     separate package (installing its files in `/usr/doc') so that it
+     can be made available with the distribution.  If a user has the
+     need for the documentation, they can easily get it from the
+     archive, CD-ROM, etc., but it should not take up disk space on the
+     machines of the user who do not need or want it installed.
+
+   * Create a file named `/usr/doc/copyright/<package>' which gives
+     details of the authorship and copyright of the package.  If the
+     package is distributed under the GNU General Public Licence, the
+     GNU Library General Public Licence or the Regents of the
+     University of California at Berkeley (BSD) licence, please say so
+     instead of including a copy of the licence.  The files `BSD',
+     `GPL', and `LGPL' will be available in the `/usr/doc/copyright'
+     directory for you to refer to.  `/usr/doc/copyright/<package>'
+     should not be compressed.
+
+     *All* authorship and copyright information from the original source
+     package must be included in the `/usr/doc/copyright/<package>'
+     file.
+
+   * Any example files (for example, sample configuration files) should
+     be placed in the directory `/usr/doc/examples'.  If the file is
+     normally a hidden file, such as `.emacs', then please call it
+     `dot.emacs', to avoid confusion.  Again, you may create a
+     subdirectory if it is needed.
+
+   * All symbolic links should be relative, not absolute.  Absolute
+     links, in general, cause problems when a file system is not
+     mounted where it "normally" resides (for example, when mounted via
+     NFS).  In certain cases, however, relative links may also cause
+     similar problems.  I have generally made links into `/etc' and
+     `/var' absolute and all other links relative.  There may be other
+     cases in which absolute links are necessary.
+
+     Therefore, in the `Makefile' or `debian.rules', do not do:
+          install: all
+                   [...]
+                   ln -fs /usr/bin/gcc /usr/bin/cc
+                   [...]
+     Instead, do:
+          ln -fs gcc /usr/bin/cc
+     or
+          ( cd /usr/bin ; ln -fs gcc cc )
+
+     Please do not create hard links in the manual page directories.  In
+     these cases, you should use relative symbolic links or files that
+     `.so' (roff for `source') others instead.
+
+   * All command scripts should have a `#!' line naming the shell to be
+     used to interpret them.
+
+   * In the case of Perl scripts this should be `#!/usr/bin/perl' or
+     sometimes `#!/bin/perl', as follows: if the script is a critical
+     one that may be called when the `/usr' partition is unmounted or
+     broken it should use `/bin/perl'.  Otherwise (especially if the
+     script is not specifically targetted at Debian) it should use
+     Perl's standard location, `/usr/bin/perl'.
+
+   * Generally the following compilation parameters should be used:
+
+             CC = gcc
+             CFLAGS = -O2 -g -Wall # sane warning options vary between programs
+             LDFLAGS = # none (or -N, if appropriate; see below)
+             install -s (or strip)
+
+     Note that all installed binaries should be stripped, either by
+     using the `-s' flag to `install', or by calling `strip' on the
+     binaries after they have been copied into the `debian-tmp' but
+     before the tree is made into a package.
+
+     Make sure that you do not link with `-g', as this makes a.out
+     compilers produce huge statically linked binaries.  The `-g' flag
+     is useful on compilation so that you have available a full set of
+     debugging symbols in your built source tree, in case anyone should
+     file a bug report involving (for example) a core dump.
+
+     `-N' should only be used on binaries that are very small (less than
+     8K with the `-N' option, roughly) and are not likely to have
+     multiple instances in memory.  Do not use `-N' on daemons, no
+     matter how small they are.
+
+     It is up to the package maintainer to decide what compilation
+     options are best for the package.  Certain binaries (such as
+     computationally-intensive programs) may function better with
+     certain flags (`-O3', for example); feel free to use them.  Please
+     use good judgment here.  Don't add flags for the sake of adding
+     flags; only add flags if there is good reason to do so.
+
+   * Please make sure that you use only released versions of shared
+     libraries to build your packages; otherwise other users will not
+     be able to run your binaries properly.  Producing source packages
+     that depend on unreleased compilers is also usually a bad idea.
+
+   * Logfiles should usually be named `/var/log/<package>', or
+     `/var/log/<package>.<something>' if you have several logfiles.  It
+     may be appropriate to create a directory.  Make sure that any
+     logfiles are rotated occasionally so that they don't grow
+     indefinitely; the best way to do this is to use `savelog' from the
+     cron package in an `/etc/cron.daily', `/etc/cron.weekly' or
+     `/etc/cron.monthly' script.
+
+   * Please check with the base system maintainer (Ian Murdock) before
+     using users or groups other than `root' and others specified in
+     this document.
+
+\1f
+File: guidelines.info,  Node: Source Package,  Next: Binary Package,  Prev: Package Content,  Up: Top
+
+Source Package
+**************
+
+   The source package should contain a file called `debian.rules' which
+contains at least the following targets, to be invoked in the top level
+directory:
+
+     build
+     binary
+     clean
+
+   `debian.rules' should start with
+
+     #!/usr/bin/make -f
+
+and be executable.  It is a good idea to arrange for it not to fail
+obscurely when invoked in the wrong directory, for example by testing
+for the existence of a file in the source directory.
+
+   * The `build' target should perform all non-interactive configuration
+     and compilation of the package.  If a package has an interactive
+     pre-build configuration routine, the source package should be built
+     *after* this has taken place.
+
+     For some packages, notably ones where the same source tree is
+     compiled in different ways to produce two binary packages, the
+     `build' target does not make much sense.  For these packages it is
+     good enough to provide two (or more) targets (`build-a' and
+     `build-b' or whatever) for each of the ways of building the
+     package, and a `build' target that does nothing.  The `binary'
+     target will have to build the package in each of the possible ways
+     and make the binary package out of each.
+
+   * The `binary' target of `debian.rules' should be all that is
+     necessary for the user to build the binary package.  The binary
+     package should be created using `dpkg' and placed in the parent of
+     the top level directory.  The next section describes how to
+     construct binary packages from the `binary' target.
+
+   * The `clean' target should undo the effects of the `build' target
+     and the `binary' target, except that it should leave alone any
+     `../<package>-<version>.deb' file created by a run of `binary'.
+
+   * Additional targets may exist in `debian.rules'.  We recommend using
+     `source' and `diff' targets to build the Debianised source package
+     and the Debianisation context diff, respectively.  These files
+     should be placed in `../foo-<version>.tar.gz' and
+     `../foo-<version>.diff.gz'.  The `install' target, for installing
+     into a running system direct from the Debianised source tree, is
+     no longer required.  The sample `debian.rules' provides `source'
+     and `diff' targets that should work with little or no alteration,
+     providing that the package-specific variables at the top of the
+     script have been properly defined.
+
+   * If you need to edit a `Makefile' where `configure' scripts are
+     used, you should edit the `.in' files rather than editing the
+     `Makefile' directly.  This allows the user to reconfigure the
+     package if necessary.  You should *not* configure the package and
+     edit the generated `Makefile'!  This makes it impossible for
+     someone else to later reconfigure the package.
+
+   * Please document your changes to the source package so that future
+     package maintainers know what has been changed.  To do this,
+     include a description of your changes in the `debian.README'
+     (which, as described above, should already contain authorship and
+     copyright information!) and include relevant information such as
+     your name, electronic mail address, date, etc.  The
+     `debian.README' file should also document any `unusual' packages
+     which must be installed for this one to compile.
+
+   * If changes to the source code are made that are applicable to Linux
+     systems or systems in general please try to get them included in
+     the upstream version of the package by supplying the upstream
+     authors with the changes in whatever form they prefer.
+
+     If changes to the source code are made, please use a `define'.  If
+     they are changes required to compile or function under Linux in
+     general, use `LINUX'.  If it is a cosmetic or functional change,
+     use `DEBIAN'.
+
+   * Create the source package using `tar', and use `gzip -9' to
+     compress it.  Source packages should be named in the form
+     <package>-<version>.tar.gz--for example, `fileutils-3.9-3.tar.gz'.
+
+     NB, here `<version>' is the full Debian version number, in the
+     form `<original_version>-<debian_revision>' (see below), but the
+     tarfile should unpack into a directory named
+     `<package>-<original_version>' (again, see the section below on
+     version numbering).
+
+   * Create the context diff against the original package using `diff
+     -cNr', and use `gzip -9' to compress it.  Context diffs should be
+     named in the form <package>-<version>.diff.gz--for example,
+     `fileutils-3.9-3.diff.gz'.
+
+   Please note that the package and patch filenames do *not* need to
+fit in MS-DOS 8+3.  They will be made available under an alternative
+8+3 name in the archive by the archive maintainer, using a symlink.
+
+\1f
+File: guidelines.info,  Node: Binary Package,  Next: Control Files,  Prev: Source Package,  Up: Top
+
+Binary Package
+**************
+
+   The `binary' target of the source package `debian.rules' file should
+do the following (see the sample `debian.rules' for an implementation
+that you are free to modify and use in your own packages, of course):
+
+   * Create an empty directory in the top-level directory of the source
+     package (deleting it first, if necessary), and install the files
+     belonging to this package in that directory.  For example, the
+     directory could be called `debian-tmp' and would probably contain
+     directories `debian-tmp/usr/bin', `debian-tmp/usr/lib', etc.
+     (`debian-tmp' is the name traditionally used, and it is used in
+     the sample `debian.rules' file, so we will use that name in the
+     Guidelines.)
+
+   * Make sure that all the files under `debian-tmp' have the correct
+     ownerships and permissions (*note Package Content::., for more
+     information about file locations, ownerships, and permissions.)
+
+   * Create a subdirectory of `debian-tmp' called `DEBIAN'.  This
+     directory contains the package control information, including at
+     the very least the master information file named `control'.  The
+     next section describes the semantics and syntax of the files
+     required and allowed here.
+
+   * Run `dpkg' to create the binary package, using something like
+
+          dpkg --build debian-tmp
+
+     This will create a file called `debian-tmp.deb', from the
+     `debian-tmp' directory.  You should rename this file to
+     `../<package>-<version>.deb' after it is built.
+
+     After the `binary' target has done all this, the
+     `<package>-<version>.deb' file in the parent directory is the
+     binary distribution.  This file may be distributed and installed on
+     any Debian GNU/Linux system with `dpkg' in the same manner and
+     using the same methods as all packages are installed to the system.
+
+   * If a single source package corresponds to several binary packages,
+     there should usually be a `debian.rules' file with a single
+     `binary' target that builds all the binary packages involved and
+     move all packages to the parent directory of that containing the
+     source package.
+
+     In this case, you should choose binary package names which are
+     meant to make clear the close relationship between the binary
+     packages and which source package the binary packages came from
+     (for example, the `texinfo' source package build two binary
+     packages: `texidoc' and `texinfo').  You should place the
+     appropriate binary package name in the `Package' field of the
+     control file (not the source package name), and you should
+     consider whether the other binary packages that come from the same
+     source tree should be mentioned in the `Depends', `Recommends' or
+     `Suggests' fields.  You should put the source package name in the
+     `Source' field.
+
+     You should retain the source package version numbering in the
+     `Version' field, if possible--the version number should be the
+     same for the Debianised source tree and all the binary packages
+     generated from it.  It is more important, though, that the version
+     numbers sort correctly.  See below for details of version numbers.
+
+\1f
+File: guidelines.info,  Node: Control Files,  Next: Appendix,  Prev: Binary Package,  Up: Top
+
+Control Files
+*************
+
+   Each binary package contains, in addition to the files that comprise
+the actual package, a set of text files that control how `dpkg'
+installs, configures, upgrades, removes, etc. the package.  These files
+are called "control files".  When creating the package, the control
+files should placed in a directory called `DEBIAN', as described
+earlier (*note Binary Package::., for further information).
+
+   The control information files are:
+
+`control'
+     The master package control information file.
+
+`conffiles'
+     A list of package configuration files.
+
+`preinst'
+     The package pre-installation script.
+
+`postinst'
+     The package post-installation script.
+
+`prerm'
+     The package pre-removal script.
+
+`postrm'
+     The package post-removal script.
+
+   Of these, only `control' is required.  The various installation
+scripts, and the configuration files list, will only be used if they are
+present.
+
+* Menu:
+
+* control::
+* conffiles::
+* Installation and Removal Scripts::
+* Dependencies and Conflicts::
+* Package Classification Fields::
+
+\1f
+File: guidelines.info,  Node: control,  Next: conffiles,  Prev: Control Files,  Up: Control Files
+
+control
+=======
+
+   The `control' file contains a number of fields.  Each field begins
+with a field name, such as `Package' or `Version' (case insensitive),
+followed by a colon and optionally some spaces or tabs (a single space
+is conventional).  Then comes the body of the field, which may be
+several lines long; each continuation line must start with at least one
+space or tab.  (These are the same rules as apply to RFC822 mail
+headers.)  Blank lines are not permitted in the control file.
+
+   The required fields in the control file are the following:
+
+`Package'
+     The name of the package.
+
+`Description'
+     The description of the package.  How to write an extended and more
+     usefull description field can be found in *note How to write the
+     Description control file field::..
+
+`Maintainer'
+     The name and e-mail address of the maintainer of the package.
+
+`Version'
+     The version number in the format
+     `<original_version>-<debian_revision>'.
+
+   Each field has a particular format and meaning for the package
+installation tools.
+
+   The value of `Package' should be the name of the package.  Package
+names must start with an alphanumeric, must be at least two characters,
+and may contain only alphanumerics and the characters - + . @ : = % _
+(that is, hyphen, plus, stop, at, colon, equals, percent and
+underscore).  They are not case sensitive.
+
+   The `Maintainer' field should be in the form
+
+     Joe J. Bloggs <jbloggs@foo.com>
+
+Note that this will not be useable as an email address if the name
+given contains full stop characters, because of a silly restriction in
+the Internet mail standards.  If you want to use this as an email
+address in a program you should check for full stops and change the
+string to the form `jbloggs@foo.com (Joe J. Bloggs)' if you find any.
+
+   The `Version' field should be the version number of the package.
+For most packages which are not written specifically for Debian, this
+should be in the form
+
+     Version: <original_version>-<debian_revision>
+
+where `<original_version>' is the original package version number in
+whatever form the original package uses and `<debian_revision>'
+indicates which "debianisation" this is (this should usually be a plain
+number or perhaps a two numbers separated by a full stop, and should be
+incremented each time the package is changed or updated).
+
+   Packages which are written specifically for Debian do not have a
+debian_revision, and their version number should simply be version
+(which should not contain any hyphens, to avoid confusion).
+
+   There is an ordering imposed on version numbers, described in
+`version-ordering.txt'.  This ordering is designed to `do the right
+thing' in most circumstances; if your package has an version number in
+an unusual format you may need to reformat it somewhat to get the
+ordering right.  This is important because `dpkg' is (for example)
+reluctant to downgrade packages.
+
+   The optional fields in the control file are the following:
+
+`Depends'
+     The names of prerequisite packages.
+
+`Recommends'
+     The names of related, recommended packages.
+
+`Suggests'
+     The names of related, optional packages.
+
+`Conflicts'
+     The names of packages which conflict with this package.
+
+`Provides'
+     The names of virtual packages which this package provides.
+
+`Priority'
+     The `priority' of the package, as shown and used by `dselect'.
+
+`Section'
+     The `section' of the package, as shown and used by `dselect', and
+     used as a location for the package in the distribution.
+
+`Essential'
+     A boolean field used by the base packages.
+
+`Pre-Depends'
+     Used by base packages to ensure that (for example) shared
+     libraries are present befoore they are upgraded.
+
+`Source'
+     Gives the name of the source package when several binary packages
+     are generated from a single source tree.
+
+See below for details of the semantics and syntax of these fields.
+Most packages will need at least a `Depends' field.
+
+   An example of a `control' file would be:
+
+     Package: smail
+     Version: 3.1.29.1-13
+     Maintainer: Ian Jackson <iwj10@cus.cam.ac.uk>
+     Recommends: pine | mailx | elm | emacs | mail-user-agent
+     Suggests: metamail
+     Depends: cron, libc5
+     Conflicts: sendmail
+     Provides: mail-transport-agent
+     Description: Electronic mail transport system.
+      Smail is the recommended mail transport agent (MTA) for Debian.
+      .
+      An MTA is the innards of the mail system - it takes messages from
+      user-friendly mailer programs and arranges for them to be delivered
+      locally or passed on to other systems as required.
+      .
+      In order to make use of it you must have one or more user level
+      mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+      and VM as mailreaders) installed.  If you wish to send messages other
+      than just to other users of your system you must also have appropriate
+      networking support, in the form of IP or UUCP.
+
+   In this case, `mail-user-agent' is a virtual package representing
+any user mailer program; the actual package names `pine' is quoted for
+the reasons described in `dependency-ordering.txt', and the others
+because older versions of those packages do not have the appropriate
+`Provides' field.
+
+\1f
+File: guidelines.info,  Node: conffiles,  Next: Installation and Removal Scripts,  Prev: control,  Up: Control Files
+
+conffiles
+=========
+
+   The contents of `conffiles' is simply a list of configuration files
+in the package.  When installing the package, `dpkg' uses an
+intelligent method to update these files.  This will ensure that
+package-specific configuration files are not overwritten when a package
+is upgraded, unless the user wishes the installation tools to do so.
+
+   Typically, files listed in conffiles are package-specific
+configuration files, which (according to the Linux Filesystem Standard)
+are stored in `/etc'.  For example, the `sendmail' package may contain
+the file `/etc/sendmail.cf', which we do not wish to overwrite
+automatically when the user upgrades the sendmail package.  Only those
+files listed in `DEBIAN/conffiles' will be updated intelligently when a
+package is upgraded; all other files in the package will be overwritten
+by the upgrade process.
+
+   Configuration files which will be functional as shipped and will
+probably need little or no local editing should simply be listed the
+`conffiles' file; in this case you need read no further.
+
+   For packages whose configuration files will need modification on
+most systems there are two sensible approaches.  Which one is chosen
+depends on how hard the configuration problem is and how much time the
+package maintainer has available.
+
+   One option is for you to ship a minimal `best-effort' file in
+`/etc', and list the file in `conffiles'.  This will mean that the user
+will have to go and edit the file themselves to get the package to work
+properly, of course.  The next time they upgrade the package, if you
+haven't changed the file version, their old file will be left in place.
+If you have modified your version then the user will get a prompt
+asking them which version of the file they want, theirs or yours.  They
+will then usually have to resolve the discrepancies manually.
+
+   The other option is to be preferred, if you can do it: do not put a
+copy of the configuration file in the package at all.  Instead, you
+check in the postinst whether the file exists, and if it doesn't you
+prompt the user for the information you need to create a good one.  This
+is obviously harder work.
+
+   You also have to remember that you will have to keep up with your
+package's changes: if you discover a bug in the program which generates
+the configuration file, or if the format of the file changes from one
+version to the next, you will have to arrange for the postinst script to
+do something sensible--usually this will mean editing the installed
+configuration file to remove the problem or change the syntax.  You will
+have to do this very carefully, since the user may have changed the
+file, perhaps to fix the very problem that your script is trying to deal
+with--you will have to detect these situations and deal with them
+correctly.
+
+   If you do go down this route it's probably a good idea to make the
+program that generates the configuration file(s) a separate program in
+`/usr/sbin', by convention called package`config', and then run that if
+appropriate from the post-installation script.  The package`config'
+program should not unquestioningly overwrite an existing
+configuration--if its mode of operation is geared towards setting up a
+package for the first time (rather than any arbitrary reconfiguration
+later) you should have it check whether the configuration already
+exists, and require a `--force' flag to overwrite it.
+
+   `conffiles' should almost certainly list all the files contained in
+your package in the `/etc' directory.  There may also be other files
+somewhere that the user is expected to edit, which should also be
+included.  Note, however, that the FSSTND specifies that configuration
+files must be in `/etc'.  No Debian package should contain
+configuration files in `/usr/etc', and all programs should refer to
+configuration files in `/etc'.
+
+For example, the TCP/IP package might use a conffiles which contains
+
+     /etc/init.d/netbase
+     /etc/gateways
+     /etc/protocols
+     /etc/services
+     /etc/hosts.allow
+     /etc/hosts.deny
+     /etc/rpc
+
+and so on; the files
+
+     /etc/hosts
+     /etc/inetd.conf
+     /etc/host.conf
+     /etc/networks
+     /etc/resolv.conf
+
+might be generated by an interactive configuration program, and would
+then not be included in the package or listed in the `conffiles'.
+
+\1f
+File: guidelines.info,  Node: Installation and Removal Scripts,  Next: Dependencies and Conflicts,  Prev: conffiles,  Up: Control Files
+
+Installation and Removal Scripts
+================================
+
+   The scripts `preinst', `postinst', `prerm', and `postrm' are
+optional (Bash or Perl) scripts.  As the names would indicate, if these
+scripts exist, they will be executed before installing the package,
+after installation, before package removal, and after removal,
+respectively.
+
+   They are given arguments which indicate the precise situation and
+action being performed--see `maintainer-script-args.txt' for details of
+exactly when each of the scripts is invoked and what its arguments are.
+Extra arguments and situations may be added later, so you should not
+test the number of arguments to your script to determine the situation,
+and you should choose the sense of your `if it is this then do this
+otherwise do that' tests carefully.
+
+   These scripts can be used to perform any site-specific package
+configuration.
+
+   Because the scripts will be exectued by the dpkg front-end, it is
+guaranteed that the scripts will be executed interactively.  User input
+from the scripts should be read from standard input, not the user's
+terminal.  Similarly, output should be sent to standard output.
+
+   If your maintainer scripts need to prompt for passwords and/or do
+full-screen interaction should do these things to and from `/dev/tty',
+since `dpkg' will at some point redirect scripts' standard input and
+output so that it can log the installation process.  Likewise, because
+these scripts may be executed with standard output redirected into a
+pipe for logging purposes, Perl scripts should set unbuffered output by
+setting `$|=1' so that the output is printed immediately rather than
+being buffered.
+
+   The scripts must be idempotent, and they must clean up after
+themselves properly.  Ie, they must do the right thing if run multiple
+times, even if previous runs failed halfway through.  This is so that if
+any errors occur, or if the `dpkg' run is interrupted, the user can
+recover by rerunning `dpkg', and/or by upgrading to a new version and
+then rerunning the failed operation.
+
+   These scripts should avoid producing output which it is unnecessary
+for the user to see and should rely on `dpkg' to stave off boredom on
+the part of a user installing many packages.  This means, amongst other
+things, using the `--quiet' option on `install-info'.
+
+   Packages should try to minimise the amount of prompting they need to
+do, and they should ensure that the user will only every be asked each
+question once.  This means that packages should try to use appropriate
+shared configuration files (such as `/etc/papersize' and
+`/etc/news/server'), rather than each prompting for their own list of
+required pieces of information.
+
+   It also means that an upgrade should not ask the same questions
+again, unless the user has used `dpkg --purge' to remove the package's
+configuration.  The answers to configuration questions should be stored
+in an appropriate place in `/etc' so that the user can modify them, and
+how this has been done should be documented.
+
+   If a package has a vitally important piece of information to pass to
+the user (such as "don't run me as I am, you must edit the following
+configuration files first or you risk your system emitting
+badly-formatted messages"), it should display this in the `postinst'
+script and prompt the user to hit Return to acknowledge the message.
+Copyright messages do not count as vitally important (they belong in
+`/usr/doc/copyright'; neither do instructions on how to use a program
+(these should be in on line documentation, where all the users can see
+them).
+
+   They should return a zero exit status for success, or a nonzero one
+for failure.  Note that if a script is a `#!/bin/sh' script it should
+probably start with `set -e', to avoid continuing after errors--see
+`bash'(1) for details.  Perl scripts should check for errors when
+making calls such as `open', `print', `close', `rename' and `system'.
+
+   If these scripts exist they should be left in the `DEBIAN' directory
+with execute permission enabled and should contain an appropriate `#!'
+line, such as `#!/bin/bash' for a `bash' script or `#!/bin/perl' for a
+Perl script (see above).
+
+\1f
+File: guidelines.info,  Node: Dependencies and Conflicts,  Next: Package Classification Fields,  Prev: Installation and Removal Scripts,  Up: Control Files
+
+Conflicts, Depends, Suggests, Recommends and Provides
+=====================================================
+
+   The `Depends' field lists packages that are required for this
+package to provide a significant amount of functionality.  The package
+maintenance software will not allow a package to be installed without
+also installing packages listed in its `Depends' field, and will run
+the `postinst' scripts of packages listed in `Depends' fields before
+those of the packages which depend on them, and run the `prerm' scripts
+before.
+
+   Packages containing dynamically-linked executable binaries (this
+includes almost all C programs) should include a `Depends' field which
+mentions the shared C library required for the program to run.  For
+a.out binaries linked against `libc.so.4' the relevant package name is
+`libc' (for the a.out stable 0.93 tree) or `libc4' (for the unstable
+development 1.1 tree); for ELF binaries linked against `libc.so.5' the
+relevant package name is `libc5'.
+
+   The `Recommends' field lists packages that would be found together
+with this one in all but unusual installations.  The user-level package
+maintenance program `dselect' will warn the user if they select a
+package without those listed in its `Recommends' field.  Note that
+`Recommends' fields do not currently have any implications for the
+order in which the maintainer scripts are run.
+
+   The `Suggests' field lists packages that are related to this one and
+can perhaps enhance its usefulness, but without which installing this
+package is perfectly reasonable.  The package maintenance software will
+not moan at the user for not selecting `Suggests' related packages, but
+may use the information in the `Suggests' field to assist the user
+during package selection.
+
+   The syntax of `Depends', `Recommends' and `Suggests' is a list of
+groups of alternative packages.  Each group is a list of packages
+separated by vertical bar (or `pipe') symbols, `|'.  The groups are
+separated by commas.  Each package is a package name optionally
+followed by a version number specification in parentheses.  A version
+number may start with a `>=', in which case that version or any later
+will match, or `<=' for that version or any earlier version. A version
+number starting with a `>>' or `<<' will respectively match any later
+or earlier version. If a version number or a version number starting
+with `=' is specified an exact match is required. Commas are to be read
+as `AND', and pipes as `OR', with pipes binding more tightly.
+
+   Versions of dpkg before 1.0.9 used `<' and `>' for `<=' and `>='
+(these are still supported for backward compatibility), and did not
+support `<<' and `>>'.
+
+   The `Conflicts' field lists packages that conflict with this one,
+for example by containing files with the same names (an example would
+be Smail vs. Sendmail).  The package maintenance software will not
+allow conflicting packages to be installed.  Two conflicting packages
+should each include a `Conflicts' line mentioning the other.
+
+   The syntax of `Conflicts' is a list of package names (with optional
+version numbers), separated by commas (and optional whitespace).  In
+the `Conflicts' field the comma should be read as `OR'.
+
+   The `Provides' field lists the names of any `virtual packages' of
+which this packages is to be considered an instantiation.  Virtual
+packages are used to allow packages to refer to a service they require
+(such as the availability of `/usr/sbin/sendmail') without having to
+know the names of all the relevant packages.  The virtual package names
+defined in `Provides' fields may be used in other packages' `Depends',
+`Recommends', `Suggests' and `Conflicts' fields.  For more information
+about how to use virtual packages and which virtual package names to
+use read *note Virtual dependencies::. and
+`doc/package-developer/virtual-package-names-list.text'.
+
+   The syntax of `Provides' is a list of package names separated by
+commas (and optional whitespace).
+
+\1f
+File: guidelines.info,  Node: Package Classification Fields,  Prev: Dependencies and Conflicts,  Up: Control Files
+
+Priority, Section and Essential
+===============================
+
+   The `Priority' and `Section' fields are used by `dselect' when
+displaying the list of packages to the user.  There is no need to put
+them into a package, since these are usually set by the distribution
+maintainers in the `Packages' file.
+
+   However, if a user installs a package which is not part of the
+standard distribution, or without downloading and updating from a new
+`Packages' file, the information about the priority and section of a
+package will be absent, and the `dselect' package listing will have the
+package listed under `unclassified'.  It is permissible for a package
+to include `Section' or `Priority' fields to improve this; however, if
+you do this you should make sure you keep the information up to date so
+that users are not shown conflicting information.  The `Section' field
+can also be used by the distribution maintainers as a suggestion about
+which section you think is most appropriate for your package.
+
+   The values for the `Section' and `Priority' fields should be
+determined by the distribution maintainers; if you don't know what to
+put in them just leave them out.  You can add them later, if you like,
+but remember that you'll then have to reissue your package if the
+distribution maintainers change the classification of your package.
+
+   The `Essential' field should only appear in packages in the
+installation's base system.  If it is set to `yes' then `dpkg' will not
+remove the package even if asked to, and will make certain minor
+modifications to its installation procedures.  The only other legal
+value is `no', which is equivalent to the absence of the field.
+
+
+
+\1f
+File: guidelines.info,  Node: Appendix,  Prev: Control Files,  Up: Top
+
+Appendix
+********
+
+* Menu:
+
+* configuration files - /etc/skel vs /usr/doc/examples::
+* How to write the Description control file field::
+* Configuration of init::
+* Maintainer script arguments and how `dpkg' does things::
+* Mail processing packages::
+* Virtual dependencies::
+
diff --git a/doc/guidelines.info-2 b/doc/guidelines.info-2
new file mode 100644 (file)
index 0000000..8018f09
--- /dev/null
@@ -0,0 +1,744 @@
+This is Info file guidelines.info, produced by Makeinfo-1.63 from the
+input file ./guidelines.texi.
+
+START-INFO-DIR-ENTRY
+* Guidelines: (guidelines).       How to make Debian packages.
+END-INFO-DIR-ENTRY
+
+\1f
+File: guidelines.info,  Node: configuration files - /etc/skel vs /usr/doc/examples,  Next: How to write the Description control file field,  Prev: Appendix,  Up: Appendix
+
+configuration files - /etc/skel vs /usr/doc/examples
+====================================================
+
+   There seems to be a certain amount of confusion about `/etc/skel'
+and `/usr/doc/examples'. The most important thing to remember is the
+following:
+
+   Files in `/etc/skel' will *automatically* be copied into *new* user
+accounts by `adduser'.  They should not be referenced there by any
+program. Files in `/usr/doc/examples' should not be installed
+automatically.
+
+   Therefore, if the program in question need a dotfile to exist in
+advance in `$HOME' to work *sensibly* that dotfile should be installed
+in `/etc/skel' (and listed in conffiles; *note conffiles::.).
+
+   However, programs that require dotfiles in order to operate sensibly
+(dotfiles that they do not create themselves automatically, that is) are
+a bad thing, and that programs should be configured by the Debian
+default installation as close to normal as possible.
+
+   Therefore, if a program in a Debian package needs to be configured in
+some way in order to operate sensibly that configuration should be done
+in a site-wide global configuration file elsewhere in `/etc' (and that
+file should be listed in conffiles).  Only if the program doesn't
+support a site-wide default configuration should a default per-user file
+be placed in `/etc/skel' (and listed in conffiles; *note conffiles::.).
+
+   The idea is as follows:
+
+   The sysadmin should ideally not have to do any configuration other
+than that done (semi-)automatically by the postinst script.
+
+   However, if they wish to change their configuration themselves
+(because the configuration they want is beyond the scope of the
+autoconfiguration, or because the autoconfiguration doesn't exist yet,
+or because they just want to do it themselves for any reason) then
+`/usr/doc/examples' exists as *documentation* for their benefit.
+
+   The only time these files should be read are by the sysadmin using
+their favourite editor or pager, or *perhaps* (in very complex packages)
+by the postinst as a template to build on or modify.
+
+   `/etc/skel' is part of the *implementation* of this configuration.
+It contains the files that are copied into new user accounts.  It
+should probably be as empty as we can make it.
+
+   Examples:
+`.profile'
+     `/etc/skel' should not contain a `.profile' file.  Anything that
+     needs to be done there should be done in `/etc/profile'.  Anything
+     that should not go in `/etc/profile' (users can't avoid running
+     `/etc/profile') probably should not be in the default
+     configuration.  bash has generally good default behaviour.
+
+`.bash_logout'
+     Likewise, bash functions perfectly happily without a
+     `.bash_logout', so none should be provided, since anything in it is
+     a deviation from the sensible default behaviour.
+
+`.xsession'
+     `/etc/skel' should not contain a `.xsession'.  `xdm''s system-wide
+     startup file `/usr/lib/X11/xdm/Xsession' supports a system-wide
+     default user configuration (which should probably be
+     `/etc/X11/Xsession' or some such) which may be overridden by
+     `.xsession' in the user's home directory.  Therefore there is no
+     need for a `.xsession' to be installed by default and none should
+     be provided.
+
+     Instead, a sensible `/etc/X11/Xsession' should be provided, and if
+     desired this can be used as a template by users who wish to install
+     their own configuration, or alternatively a more comprehensive
+     example with much commented-out interesting stuff could be put in
+     `/usr/doc/examples'.
+
+     If the sysadmin wishes to change the system-wide default they
+     should probably do this by editing `/etc/X11/Xsession' rather than
+     creating the file in `/etc/skel', because the former will affect
+     all user accounts that haven't explicitly overridden things by
+     creating their own file while the latter will only affect new
+     accounts.
+
+     All the configuration necessary for a program to function should be
+     provided.  Therefore sysadmins will not need to go through
+     `/usr/doc/examples' while editing configuration files in `/etc'
+     except in extreme cases (like INN) where the configuration was too
+     difficult to do automatically.
+
+`site-wide defaults'
+     Site-wide defaults should not go in `/etc/skel'.  In the case of
+     twm, for example, the system-wide default should be in
+     `/etc/X11/system.twmrc'.  (The default location for this in X11R5,
+     btw, is in `/usr/lib/X11' somewhere, but we can't put it on `/usr'
+     because of CDROM distributions, etc - hence the FSSTND's mandate
+     to put configuration files in `/etc'.)
+
+`.twmrc'
+     There should be no `.twmrc' file in `/etc/skel'.  You can have one
+     in `/usr/doc/examples' if you *like*, but why bother if
+     `system.twmrc' is a good example (and indeed is the one the user is
+     using before they create their own)?
+
+`m4'
+     `/usr/doc/examples' isn't mainly for example *configuration
+     files*.  It's for any kind of example file distributed with a
+     package.  For example, GNU m4 comes with a whole pile of example
+     m4 macro scripts, which is exactly what `/usr/doc/examples' is for.
+
+   Summary
+
+   Files that should be installed in new user accounts should be in
+`/etc/skel', as that will ensure that they *are* installed in new user
+accounts!  However, we should try to avoid the need for this.
+
+   `/usr/doc/examples' is just what it says: documentation in the form
+of examples.  If a sysadmin is required to go and read these files for
+their system to work they should be told about it.  For example, here
+is what the Smail postinst script says right at the start:
+
+     I can do certain kinds of automatic configuration of your
+     mail system, by asking you a number of questions.  Later you
+     may to confirm and/or correct your answers.  In any case,
+     comprehensive information on configuring Smail is in
+     smail(5) and in /usr/doc/examples/smail and
+     /usr/doc/smail-admin-guide.
+
+\1f
+File: guidelines.info,  Node: How to write the Description control file field,  Next: Configuration of init,  Prev: configuration files - /etc/skel vs /usr/doc/examples,  Up: Appendix
+
+How to write the Description control file field
+===============================================
+
+   The format of the `Description' field is as follows:
+
+     Description: <single line synopsis>
+      <extended description over several lines>
+
+   The extended description has several kinds of line:
+
+   * Those starting with a single space are part of a paragraph.
+     Successive lines of this form will be word-wrapped when displayed.
+     The leading space will usually be stripped off.
+
+   * Those starting with two or more spaces.  These will be displayed
+     verbatim.  If the display cannot be panned horizontally the
+     displaying program will linewrap them `hard' (ie, without taking
+     account of word breaks).  If it can they will be allowed to trail
+     off to the right.  None, one or two initial spaces may be deleted,
+     but the number of spaces deleted from each line will be the same
+     (so that you can have indenting work correctly, for example).
+
+   * Those containing a single space followed by a single full stop
+     character.  These are rendered as blank lines.  This is the *only*
+     way to get a blank line - see below.
+
+   * Those containing a space, a full stop and some more characters.
+     These are for future expansion.  *Do not* use them.
+
+   IMPORTANT and not so important TIPS:
+
+   * *Always* start extended description lines with at least *one*
+     whitespace character.  Fields in the control file and in the
+     Packages file are separated by field names starting in the first
+     column, just as in RFC822.  Forgetting the whitespace will cause
+     `dpkg-deb' (>=0.93.23) to produce a syntax error when trying to
+     build the package.  If you force it to build anyway `dpkg' will
+     refuse to install the resulting mess.
+
+   * *Do not* include any completely *empty* lines. These separate
+     different records in the Packages file, and are forbidden in
+     control files.  See the previous paragraph for what happens if you
+     get this wrong.
+
+   * The single line synopsis should be kept brief - certainly under 80
+     characters.  `dselect' displays the *first 49* characters if
+     you're using an 80-column terminal.
+
+   * Do not include the package name in the synopsis line.  The display
+     software knows how to display this already, and you do not need to
+     state it.  Remember that in many situations the user may only see
+     the synopsis line - make it as informative as you can.
+
+   * The extended description should describe what the package does and
+     how it relates to the rest of the system (in terms of, for
+     example, which subsystem it is which part of).
+
+   * Put important information first, both in the synopis and extended
+     description.  Sometimes only the first part of the synopsis or of
+     the description will be displayed.  You can assume that there will
+     usually be a way to see the whole extended description.
+
+   * You may include information about dependencies and so forth in the
+     extended description, if you wish.
+
+   * Do not use tab characters.  Their effect is not predictable.
+
+   Example control file for Smail:
+
+     Package: smail
+     Version: 3.1.29.1-13
+     Maintainer: Ian Jackson <iwj10@cus.cam.ac.uk>
+     Recommends: pine | mailx | elm | emacs | mail-user-agent
+     Suggests: metamail
+     Depends: cron, libc5
+     Conflicts: sendmail
+     Provides: mail-transport-agent
+     Description: Electronic mail transport system.
+      Smail is the recommended mail transport agent (MTA) for Debian.
+      .
+      An MTA is the innards of the mail system - it takes messages from
+      user-friendly mailer programs and arranges for them to be delivered
+      locally or passed on to other systems as required.
+      .
+      In order to make use of it you must have one or more user level
+      mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+      and VM as mailreaders) installed.  If you wish to send messages other
+      than just to other users of your system you must also have appropriate
+      networking support, in the form of IP or UUCP.
+
+\1f
+File: guidelines.info,  Node: Configuration of init,  Next: Maintainer script arguments and how `dpkg' does things,  Prev: How to write the Description control file field,  Up: Appendix
+
+Configuration of init
+=====================
+
+   The `/etc/init.d' directory contains the scripts executed by init(8)
+when init state (or "runlevel") is changed.  This includes the boot
+process, when the multi-user state begins.  Several of these scripts
+are included with init and are intended to be executed *once*, usually
+at boot time.  An example is `/etc/init.d/boot', which is executed at
+boot time to check and mount file systems, activate swap, load kernel
+modules, etc.-everything that needs to be done before the multi-user
+state begins.  `/etc/init.d' also contains the scripts that are
+executed when entering runlevel 0 (halt), runlevel 1 (single-user) and
+runlevel 6 (reboot).
+
+   Packages can (and should) place scripts in `/etc/init.d' to start or
+stop services at boot time or during a change of runlevel.  These
+scripts should be named `/etc/init.d/'<package>, and they should accept
+one of two arguments: "start", which starts the services, or "stop",
+which stops the services.  These scripts should ensure that they will
+behave sensibly if invoked with "start" when the service is already
+running, or with "stop2 when it isn't--the best way to achieve this is
+often to use `start-stop-daemon'.
+
+   This script should not fail obscurely when the configuration files
+remain but the package has been removed, as the default in dpkg is to
+leave configuration files on the system after the package has been
+removed.  Only when it is executed with the `-purge' option will dpkg
+remove configuration files.  Therefore, you should include a `test'
+statement at the top of the script, like this:
+
+     test -f <program-executed-later-in-script> || exit 0
+
+   These scripts should be referenced, when appropriate, by symbolic
+links in the `/etc/rc?.d' directories, as below.
+
+   When changing runlevels, init looks in the directory `/etc/rc<n>.d'
+for the scripts it should execute, where <n> is the runlevel that is
+being changed to.  Please note that the "scripts" in `/etc/rc?.d' are
+not actually scripts; they are symbolic links, referencing actual
+scripts in `/etc/init.d'.  For simplicity, we refer to them as
+"scripts".
+
+   First, the scripts prefixed with a "K" are executed, followed by the
+scripts prefixed with an "S".  The "K" scripts are responsible for
+killing certain services and the "S" scripts for starting certain
+services upon *entering* the runlevel.  For example, if we are changing
+from runlevel 2 to runlevel 3, init will first execute all of the "K"
+prefixed scripts it finds in `/etc/rc3.d' (to kill services), and then
+all of the "S" prefixed scripts it finds in `/etc/rc3.d' (to start
+services).  The "K" scripts will execute the file it references with an
+argument of "stop", and the "S" scripts will execute this file with an
+argument of "start".
+
+   After the "K" or "S" prefix, there should be a number specified, and
+this number should be between 00 and 99.  The number determines the
+order in which the scripts are run.  For example, the "K20" scripts will
+be executed before the "K30" scripts.  You can use this number to make
+sure that a certain service is started before another.  For example, on
+some machines, the program `setserial' may need to properly set an IRQ
+before the `ppp' program uses a modem to connect to a network.  In this
+case, the script that runs `setserial' should have a lower number than
+the script that starts `ppp' so that it runs first:
+
+     `/etc/rc2.d/S10setserial'
+     `/etc/rc2.d/S20ppp'
+
+   If it does not matter when or in which order the script is run, use
+the number "20".  If it does, then you should talk to the maintainer of
+the `sysvinit' package or post to `debian-devel', and they will help
+you choose a number.
+
+   In Debian GNU/Linux, we try to ship our software in as much of a
+"default" state as possible.  Therefore, unless there is a good reason
+for doing differently, we ask that you start and stop the services in
+each of the multi-user state runlevels (2, 3, 4, and 5).  If a service
+needs to be stopped before a file system can be unmounted (an example is
+process accounting or quota services), then be sure to stop them in the
+halt runlevel (0), the single-user runlevel (1) and the reboot runlevel
+(6).
+
+   The system administrator will have the opportunity to customize
+runlevels by simply adding, moving, or removing the symbolic links in
+`/etc/rc?.d'.  This is why we default to running everything in the
+multi-user state-a reasonable default-and the administrator can easily
+customize init to be as complex and sophisticated as he or she wants it
+to be beyond this.
+
+   We provide a script, `update-rc.d', to make it easier for package
+maintainers to arrange for the proper creation and removal of
+`/etc/rc?.d' symbolic links from their postinst and postrm scripts.
+You should use this script to make changes to `/etc/rc?.d' and *never*
+include any `/etc/rc.?.d' symbolic links in the actual archive.
+
+   * In the postinst script, you need only do the following to setup
+     `/etc/rc?.d'.  You should redirect standard output to `/dev/null',
+     as `update-rc.d' produces insignificant output:
+
+          update-rc.d <package> default >/dev/null
+
+     where <package> is the name of the file as it appears in
+     `/etc/init.d'.  It will use the default number of "20", as
+     mentioned above.  If you need to use a different number, you can
+     specify it after "default":
+
+          update-rc.d <package> default 30 >/dev/null
+
+   * In the postrm script, you need only do the following *if and only
+     if* it is called with the `purge' argument:
+
+          if [ purge = "$1" ]
+          then
+            update-rc.d <package> remove >/dev/null
+          fi
+
+Important Note:
+---------------
+
+   *Do not* include the `/etc/rc?.d/*' symbolic links in the archive!
+*This will cause problems!*  You should create them with update-rc.d,
+as above.
+
+   *Do not* include the `/etc/rc?.d/*' symbolic links in conffiles!
+*This will cause problems!*  *Do*, however, include the `/etc/init.d'
+scripts in conffiles.
+
+Example:
+--------
+
+   The process accounting package wants to make sure that process
+accounting is started at boot time and that it is stopped before the
+system is halted, enters the single-user state, or is rebooted (so that
+the `/var' file system can be properly unmounted).  It puts a script
+that does this in `/etc/init.d', naming the script appropriately
+"acct".  This script accepts one of two arguments: either "start",
+which starts process accounting, or "stop", which stops it.  To ensure
+that it does not fail obscurely when the configuration files remain but
+the package has been removed, we include a `test' statement at the top
+of the script:
+
+     #! /bin/sh
+     #
+     # Start process accounting.
+     . /etc/init.d/functions
+     test -f /usr/sbin/accton || exit 0
+     case "$1" in
+       start)
+         echo "Starting process accounting"
+         /usr/sbin/accton /var/account/pacct
+         ;;
+       stop)
+         echo "Stopping process accounting"
+         /usr/sbin/accton
+         ;;
+       *)
+         echo "Usage: /etc/init.d/acct {start|stop}"
+         exit 1
+     esac
+     exit 0
+
+   You may find a skeletal script from which to base your `/etc/init.d'
+scripts in `/etc/init.d/skeleton'.
+
+   We want to stop then (re)start process accounting when entering a
+multi-user state-runlevels 2, 3, 4, and 5-and we want to stop it when
+leaving such a state-runlevels 0 (halt), 1 (single) and 6 (reboot).
+These are good defaults, and we accomplish this by including the
+following in the postinst:
+
+     update-rc.d acct default >/dev/null
+
+   When the user removes the acct packages with the `-purge' option, we
+want to make sure the `/etc/rc?.d' symbolic links are properly removed,
+so we include the following in the postrm:
+
+     update-rc.d acct remove >/dev/null
+
+   Otherwise, the `/etc/rc?.d' symbolic links will remain on the system
+along with `/etc/init.d/acct' script.
+
+\1f
+File: guidelines.info,  Node: Maintainer script arguments and how `dpkg' does things,  Next: Mail processing packages,  Prev: Configuration of init,  Up: Appendix
+
+Maintainer script arguments and how `dpkg' does things
+======================================================
+
+   This appendix describes exactly how maintainer scripts are called,
+with what arguments, in what order, and what `dpkg' does in between.
+
+   In all cases version numbers are <version>-<revision>, if the package
+has both, or just <version>.  `upgrade' is used even when the new
+version number looks lower than the old.
+
+Summary
+-------
+
+     <new preinst> install
+     <new preinst> install <old-version>
+     <new preinst> upgrade <old-version>
+     <old preinst> abort-upgrade <new-version>
+     
+     <postinst> configure
+     <old postinst> abort-upgrade <new version>
+     <conflictor's postinst> abort-remove in-favour <package> <new version>
+     <deconfigured's postinst> abort-deconfigure \
+                   in-favour <package-being-installed-but-failed> <version>
+                   removing <conflicting-package> <version>
+     
+     <prerm> remove
+     <old prerm> upgrade <new version>
+     <new prerm> failed-upgrade <old-vppersion>
+     <conflictor's prerm> remove in-favour <package> <new version>
+     <deconfigured's prerm> deconfigure \
+                   in-favour <package-being-installed> <version> \
+                   removing <conflicting-package> <version>
+     
+     <postrm> remove
+     <postrm> purge
+     <old postrm> upgrade <new-version>
+     <new postrm> failed-upgrade <old-version>
+     <new postrm> abort-install
+     <new postrm> abort-install <old-version>
+     <new postrm> abort-upgrade <old-version>
+     <disappearer's postrm> disappear <overwriter> <new version>
+
+Details of unpack phase of installation or upgrade
+--------------------------------------------------
+
+   The procedure on installation/upgrade/overwrite/disappear (ie, when
+running `dpkg --unpack', or the unpack stage of `dpkg --install') is as
+follows.  In each case if an error occurs the actions in are general
+run backwards - this means that the maintainer scripts are run with
+different arguments in reverse order.  These are the `error unwind'
+calls listed below.
+
+  1.
+       a. If a version the package is already installed, call
+               <old prerm> upgrade <new version>
+
+       b. If this gives an error (ie, a non-zero exit status), dpkg will
+          attempt instead:
+               <new prerm> failed-upgrade <old-version>
+           error unwind, for both the above cases:
+               <old postinst> abort-upgrade <new version>
+
+  2. If a `conflicting' package is being removed at the same time:
+       a. If any packages depended on that conflicting package and
+          `--auto-deconfigure' is specified, call, for each such
+          package:
+               <deconfigured's prerm> deconfigure \
+                in-favour <package-being-installed> <version> \
+                removing <conflicting-package> <version>
+           error unwind:
+               <deconfigured's postinst> abort-deconfigure \
+                in-favour <package-being-installed-but-failed> <version>
+                removing <conflicting-package> <version>
+          The deconfigured packages are marked as requiring
+          configuration, so that if -install is used they will be
+          configured again if possible.
+
+       b. To prepare for removal of the conflicting package, call:
+               <conflictor's prerm> remove in-favour <package> <new version>
+           error unwind:
+               <conflictor's postinst> abort-remove in-favour <package> <new version>
+
+  3.
+       a. If the package is being upgraded, call
+               <new preinst> upgrade <old-version>
+
+       b. otherwise, if the package had some configuration files from a
+          previous version installed (ie, it is in the conffiles-only
+          state):
+               <new preinst> install <old-version>
+
+       c. otherwise (ie, the package was completely purged):
+               <new preinst> install
+           error unwind versions, respectively:
+               <new postrm> abort-upgrade <old-version>
+               <new postrm> abort-install <old-version>
+               <new postrm> abort-install
+
+  4. The new package's files are unpacked, overwriting any that may be
+     on the system already, for example any from the old package or
+     from another package (backups of the old files are left around,
+     and if anything goes wrong dpkg will attempt to put them back as
+     part of the error unwind).
+
+  5.
+       a. If the package is being upgraded, call
+               <old postrm> upgrade <new-version>
+
+       b. If this fails, dpkg will attempt:
+               <new postrm> failed-upgrade <old-version>
+           error unwind, for both cases:
+               <old preinst> abort-upgrade <new-version>
+          This is the point of no return - if dpkg gets this far, it
+     won't back off past this point if an error occurs.  This will
+     leave the package in a fairly bad state, which will require a
+     successful reinstallation to clear up, but it's when dpkg starts
+     doing things that are irreversible.
+
+  6. Any files which were in the old version of the package but not in
+     the new are removed.
+
+  7. The new file list replaces the old.
+
+  8. The new maintainer scripts replace the old.
+
+  9. Any packages all of whose files have been overwritten during the
+     installation, and which aren't required for dependencies, are
+     considered to have been removed.  For each such package,
+       a. dpkg calls:
+               <disappearer's postrm> disappear <overwriter> <new version>
+
+       b. The package's maintainer scripts are removed.
+
+       c. It is noted in the status database as being in a sane state,
+          namely not installed (any conffiles it may have are ignored).
+          Note that disappearing packages do not have their prerm
+          called, because dpkg doesn't know in advance that the package
+          is going to vanish.
+
+ 10. Any files in the package we're unpacking that are also listed in
+     the file lists of other packages are removed from those lists.
+     (This will lobotomise the file list of the `conflicting' package
+     if there is one.)
+
+ 11. The backup files made at 4. are deleted.
+
+ 12. The new package's status is now sane, and recorded as `unpacked'.
+     Here is another point of no return - if the conflicting package's
+     removal fails we do not unwind the rest of the installation; the
+     conflicting package is left in a half-removed limbo.
+
+ 13. If there was a conflicting package we go and do the removal
+     actions, starting from point 2. of the removal, below.
+
+Details of configuration
+------------------------
+
+   When we configure a package (this happens with `dpkg --install', or
+with `--configure'), we first update the conffiles and then call:
+     <postinst> configure <most-recently-configured-version>
+
+   No attempt is made to unwind after errors during configuration.
+
+Details of removal and/or configration purging
+----------------------------------------------
+
+  1.      <prerm> remove
+
+  2. The package's files are removed (except conffiles).
+
+  3.      <postrm> remove
+
+  4. All the maintainer scripts except the postrm are removed.
+
+     If we aren't purging the package we stop here.  Note that packages
+     which have no postrm and no conffiles are automatically purged
+     when removed, as there is no difference except for the dpkg status.
+
+  5. The conffiles and any backup files (`~'-files, `#*#' files,
+     `%'-files, .dpkg-{old,new,tmp}, etc.) are removed.
+
+  6.      <postrm> purge
+
+  7. The package's file list is removed.
+        No attempt is made to unwind after errors during removal.
+
+\1f
+File: guidelines.info,  Node: Mail processing packages,  Next: Virtual dependencies,  Prev: Maintainer script arguments and how `dpkg' does things,  Up: Appendix
+
+Mail processing packages
+========================
+
+   Debian packages which process electronic mail (whether
+mail-user-agents (MUA) or alternative mail-transport-agents (MTA))
+*must* make sure that they are compatible with the configuration
+decisions below.  Failure to do this may result in lost mail, broken
+`From:' lines, and other serious brain damage!
+
+   * The mail spool is `/var/spool/mail' and the interface to send a
+     mail message is `/usr/sbin/sendmail' (as per the FSSTND).  The mail
+     spool is part of the base and not part of the MTA package.
+
+   * Mailboxes are locked using the `.lock' lockfile convention, rather
+     than fcntl, flock or lockf.
+
+   * Mailboxes are generally 660 `<user>.mail' unless the user has
+     chosen otherwise.  A MUA may remove a mailbox (unless it has
+     nonstandard permissions) in which case the MTA or another MUA must
+     recreate it if needed.  Mailboxes must be writeable by group mail.
+
+   * The mail spool is 2775 mail.mail, and MUA's need to be setgid mail
+     to do the locking mentioned above (and obviously need to avoid
+     accessing other users' mailboxes using this privilege).
+
+   * `/etc/aliases' is the source file for the system mail aliases (e.g.
+     postmaster, usenet, etc.) - it is the one which the sysadmin and
+     postinst scripts may edit.
+
+   * The convention of writing `forward to <address>' in the mailbox
+     itself is not supported.  Use a `.forward' file instead.
+
+   * The location for the `rmail' program used by UUCP for incoming mail
+     is `/usr/sbin/rmail', as per the FSSTND.  Likewise, `rsmtp', for
+     receiving batch-SMTP-over-UUCP, is in `/usr/sbin/rsmtp' if it is
+     supported.
+
+   * Smail is not using HoneyDanBer UUCP, whose uux apparently accepts
+     -a and -g options.
+
+   * If you need to know what name to use (for example) on outgoing
+     news and mail messages which are generated locally, you should use
+     the file `/etc/mailname'.  It will contain the portion after the
+     username and `@' sign for email addresses of users on the machine
+     (followed by a newline).
+
+   A package should check for the existence of this file.  If it exists
+it should use it without comment (1).  If it does not exist it should
+prompt the user for the value and store it in `/etc/mailname' as well
+as using it in the package's configuration.  The prompt should make it
+clear that the name will not just be used by that package.  E.g., in
+the same situation the INN package says:
+
+     Please enter the `mail name' of your system.  This is the hostname
+     portion of the address to be shown on outgoing news and mail messages.
+     The default is `$syshostname', your system's host name.
+     Mail name [`$syshostname']:
+   ($syshostname is the output of `hostname -fqdn').
+
+   ---------- Footnotes ----------
+
+   (1)  An MTA's prompting configuration script may wish to prompt the
+user even if it finds this file exists.
+
+\1f
+File: guidelines.info,  Node: Virtual dependencies,  Prev: Mail processing packages,  Up: Appendix
+
+Virtual dependencies
+====================
+
+   Virtual packages are in the same namespace as real packages, and may
+have the same name.  The meaning of a virtual package in a
+dependency/conflicts list is exactly that of listing all the real
+packages which state that they are an instantiation of that virtual
+package.
+
+   This is done with a new Provides field in the control file, with a
+syntax much like the Conflicts field.
+
+   The idea is that we can have something like:
+     Package: elm
+     Depends: mta
+     
+     Package: smail
+     Provides: mta
+     Conflicts: mta
+     
+     Package: sendmail
+     Provides: mta
+     Conflicts: mta
+    The result is equivalent to elm having said
+     Package: elm
+     Depends: smail | sendmail
+
+   (There'll be a special case to say that a package may conflict with a
+virtual package which it provides - clearly ...)
+
+   If there are both a real and a virtual package of the same name then
+the dependency may be satisfied (or the conflict caused) by either the
+real package or any of the virtual packages which provide it.  This is
+so that, for example, supposing we have
+     Package: lout
+     Optional: ghostview
+   (this is a fictional example - the Lout package should not mention
+ghostview), and someone else comes up with a nice PostScript previewer,
+then they can just say
+     Package: marvelpostview
+     Provides: ghostview
+   and all will work in the interim (until, say, the Lout maintainer
+changes things).
+
+   If a dependency or a conflict has a version number attached then only
+real packages will be considered to see whether the relationship is
+satisfied (or prohibited, for a conflict) - it is assumed that a real
+package which provides virtual package is not of the `right' version.
+If there is demand it can be arranged that a package which provides a
+virtual package may mention a version number, though this is unlikely to
+be helpful:
+     Provides: mta (2.0)
+
+   If you want to specify which of a set of real packages should be the
+default to satisfy a particular dependency on a virtual package, you can
+simply list the real package as alternative before the virtual one:
+     Package: xbaseR6
+     Recommended: xsvga | x-server
+     Provides: x-base, xr6shlib
+     
+     Package: xsvga
+     Recommended: x-base
+     Provides: x-server
+     
+     Package: x8514
+     Recommended: x-base
+     Provides: x-server
+
+   Virtual package names should generally not be used in the names of
+`/etc/init.d' scripts, configuration files, logfiles, and so on, so
+that several programs providing the same virtual package name can be
+installed.
+
+
diff --git a/doc/guidelines.texi b/doc/guidelines.texi
new file mode 100644 (file)
index 0000000..78662e4
--- /dev/null
@@ -0,0 +1,1936 @@
+\input texinfo @c -*-texinfo-*-
+@setfilename guidelines.info
+
+@set DATE 26th January 1996
+
+@setchapternewpage off
+
+@iftex
+@center @titlefont{Debian GNU/Linux Packaging Guidelines}
+@tex
+\vskip2pt \hrule height 2pt width \hsize \vskip2pt
+@end tex
+@sp 0.5
+@center @value{DATE}
+@end iftex
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Guidelines: (guidelines).       How to make Debian packages.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@node Top, Additional Information, (dir), (dir)
+
+@ifinfo
+@top Debian GNU/Linux Packaging Guidelines
+@end ifinfo
+
+   This file documents the steps that must be taken in the preparation
+of a Debian GNU/Linux package.  All submissions to be included in the
+distribution proper and all packages to be considered for @file{contrib}
+or @file{non-free} availability @emph{must} conform to the guidelines
+and standards described in this document or they cannot be included or
+made available at the archive with the distribution.
+
+   Please read the Guidelines carefully.  If you have comments or
+questions, please contact @code{debian-devel@@pixar.com}.  If you are
+planning on going further than just contributing a package (i.e., if
+you plan to maintain it for an extended period of time or if you are
+generally interested in becoming more involved in the Project), you
+should join the @code{debian-devel} mailing list.  For more details,
+read @file{info/mailing-lists.txt}, available at any Debian GNU/Linux
+archive.
+
+   (This file was last updated on @value{DATE}.  Please check the most
+recent @file{dpkg} package at any Debian GNU/Linux archive for a
+potentially more up to date copy.)
+
+@menu
+* Additional Information::      Where other info is to be found.
+* Package Copyright::           A few words about the importance of
+                                understanding the package copyright.
+* Package Content::             Requirements for the package content.
+* Source Package::              Creating the source package.
+* Binary Package::              Creating the binary package.
+* Control Files::               The binary package control files.
+* Appendix::                    More specific details about some aspects.
+@end menu
+
+
+
+@node Additional Information, Package Copyright, Top, Top
+@unnumbered Additional Information
+
+   These Guidelines are intended to be fairly general.  More specific
+information is available about certain aspects of building packages,
+such as how to use the features of Init under Debian GNU/Linux and how
+to interact with some more technical details of dpkg's operation.  This
+information can be found in the directory @file{doc/package-developer}
+at any Debian GNU/Linux archive.  At the time of this writing, the
+following documents are available:
+
+@table @file
+@item virtual-package-names-list.text
+The list of virtual package names currently in use, together with the
+procedure for getting new virtual package names allocated.
+@item auto-deconfiguration.txt
+How dpkg can sometimes automatically deconfigure packages in order to
+do bulk installations smoothly.
+@item dpkg-essential-flag.txt
+How to tell dpkg a package is essential and should not be removed.
+(This is for the use of base system packages only.)
+@item dpkg-disappear-replace.txt
+What happens when a package appears to have been completely replaced.
+@end table
+
+   In the future, we hope also to make available:
+
+@table @file
+@item copyright.txt
+How to choose a good copyright notice to attach to new programs.
+@item version-ordering.txt
+The algorithm with which packages' version numbers are compared.
+@end table
+
+   Also, you should download the sample files and the sample package
+(GNU Hello) available in @file{standards/samples}.  You may use any
+of this material as a starting point for new packages.  The following
+sample files, incidentally, are available:
+
+@itemize @bullet
+@item debian.README
+@item debian.control
+@item debian.postinst
+@item debian.postrm
+@item debian.rules
+@end itemize
+
+Some more detailed information about certain topics is available in the
+appendix to this document (@pxref{Appendix}).
+
+
+@node Package Copyright, Package Content, Additional Information, Top
+@unnumbered Package Copyright
+
+   Please study the copyright of your submission @emph{carefully}
+and @emph{understand it} before proceeding!  If you have doubts or
+questions, please ask!
+
+   In order to understand how we classify and distribute certain
+packages, it is important to understand the distinction between being
+freely available and being freely redistributable.
+
+   Being @dfn{freely available}, quite simply, means that the software
+can be made available freely, at least for non-commercial purposes and
+in its original, unmodified form.  This includes packages made available
+freely that have restrictions on non-commercial use, redistribution of
+modifications, etc.  Being freely available, therefore, has nothing to
+do with being able to modify and redistribute the software.  It only
+means that you can get a copy of the software without having to pay
+(and it does not necessarily mean that you can @emph{use} the software
+without having to pay---shareware is an example of freely available
+software).
+
+   @dfn{freely redistributable}, while generally being freely available,
+goes beyond just being freely available.  Freely redistributable means
+that that the software, in addition to being able to be made available
+freely, must be able to be freely modified and redistributed without
+restriction.
+
+   All submissions to be included in the distribution proper @emph{must}
+be freely redistributable.
+
+   In addition to the distribution, the Project maintains two separate
+archives of software packages with the distribution: the @file{contrib}
+archive and the @file{non-free} archive.
+
+   @file{contrib} is an archive of user-contributed packages that are
+not maintained by the Project, packages that were once maintained by the
+Project but that are no longer actively maintained, and packages that
+are maintained by the Project but that are not yet considered ready for
+inclusion in the distribution proper (i.e., ALPHA and BETA packages).
+As above, all submissions for inclusion in the @file{contrib} archive
+@emph{must} be freely redistributable.
+
+   @file{non-free} is an archive of packages with either restrictive or
+unclear terms of copying or modification.  If a package has @emph{any}
+restrictions on modification or redistribution, it can not be included
+in the distribution or @file{contrib} archive.  It can only be included
+in the @file{non-free} archive, and then only if it is freely available.
+
+   In summary, in order to be included in the distribution proper or the
+@file{contrib} archive, a package must be @emph{freely redistributable}.
+Anyone must be able to make copies of it, modify it, redistribute it with
+their modifications in place, include it on a CD-ROM, or generally sell
+it.  To be included in the @file{non-free} archive, a package may have
+restrictions, as long as the package remains @emph{freely available}.  We
+must be available to make it available freely at the archive, and anyone
+must be able to make copies of it and use it for at least non-commercial,
+personal purposes.  Software that will typically be included in
+@file{non-free} are software that does not allow commercial distribution,
+software that does not allow modification or redistribution of
+modifications, commercial ``demos'', and ``shareware''.
+
+   When in doubt, send mail to @file{iwj10@@cus.cam.ac.uk} and
+@file{imurdock@@debian.org}.  Be prepared to provide us with the
+copyright statement.  Software covered by the GPL, public domain
+software and BSD-like copyrights are safe; be wary of the phrases
+``commercial use prohibited'' and ``distribution restricted''.
+
+   Every package submission @emph{must} be accompanied by verbatim copy
+of its copyright (with the exceptions of public domain packages and
+those covered by the UCB BSD licence or the GNU GPL or LGPL; in these
+cases simply indicate which is appropriate).  This information must be
+included in a file installed to the directory @file{/usr/doc/copyright}.
+See below for details.
+
+
+
+@node Package Content, Source Package, Package Copyright, Top
+@unnumbered Package Content
+
+   The following requirements apply equally to both the binary and
+source packages.  In either case, when files have been installed,
+they must conform to the requirements described in this section.
+
+   The primary rule in Debian GNU/Linux is to follow the Linux @dfn{File
+System Standard} (@dfn{FSSTND}).  The location of installed files
+@emph{must} comply @emph{fully} with the FSSTND.  The latest version of
+this document can be found alongside the Guidelines or at
+@file{tsx-11.mit.edu} in @file{/pub/linux/docs/linux-standards/fsstnd}.
+Specific questions about following the standard should be addressed to
+Daniel Quinlan, the FSSTND coordinator, at @code{quinlan@@yggdrasil.com}.
+
+   In addition to the FSSTND, all Debian GNU/Linux packages must follow
+the guidelines below.
+
+@itemize @bullet
+@item
+Directories should be mode 755 or (for group-writability) mode 2775,
+with the exception of special ``system'' directories that need to be
+another mode.  The ownership of the directory should be consistent with
+its mode---if a directory is mode 2775, it should be owned by the group
+that needs write access to it, of course.  Use common sense in assigning
+permissions and ownerships to directories, and make sure that what is
+done is secure if it is ``non-standard''.
+
+@item
+Normal binaries should be mode 755 and owned by @code{root.root}.  If
+there is a good reason to use a different mode or ownership, you may do
+so, but you must try to be as consistent as possible with the rest of
+the system.  If you need to use a different mode or ownership, please
+discuss it with @code{imurdock@@debian.org}.
+
+@item
+Setuid binaries should normally be mode 4755 (not 4711!) and, of course,
+owned by the appropriate user.
+
+@item
+Setgid binaries should normally be mode 2755 (not 2711!) and, of course,
+owned by the appropriate group.
+
+@item
+Library files should generally be mode 644 and owned by
+@code{root.root}.  If the package requires different permissions
+or ownerships to function correctly, they should be used instead.
+
+@item
+Manual pages should be mode 644 and owned by @code{root.root}.  The
+@file{nroff} source must be installed.  You should @emph{not} install a
+preformatted ``cat page'', and you should only use sections 1 to 9---see
+the FSSTND for more details.  If no manual page is available for a
+particular program, utility or function and this is reported as a bug on
+debian-bugs, a symbolic link from the requested manual page to the
+@file{undocumented}(7) manual page should be provided. This symbolic
+link can be created from @file{debian.rules} like this:
+
+@smallexample
+ln -s ../man7/undocumented.7 debian-tmp/usr/man/man[1-9]/the_requested_manpage.[1-9]
+@end smallexample
+
+Do not close the bug report until a proper manpage is available.  You
+may forward the complaint to the upstream maintainers, and mark the bug
+as forwarded in the Debian bug tracking system.  The GNU Project do not
+in general consider the lack of a manpage to be a bug, but we do - if
+they tell you to go away leave the bug open anyway.
+
+@item
+Info documents should be mode 644, owned by @code{root.root}, and
+compressed with @file{gzip -9} when installed.  The package must call
+@file{install-info} to update the Info @file{dir} file.  This should
+be done in the post-installation script (@file{postinst}), like this:
+
+@smallexample
+install-info --quiet /usr/info/foobar.info
+@end smallexample
+
+The entries should be removed by the pre-removal script (@file{prerm}),
+like this:
+
+@smallexample
+install-info --quiet --remove /usr/info/foobar.info
+@end smallexample
+
+It is also a good idea to specify a section for the Info @file{dir}
+entry.  This is done with the @file{--section} switch.  To determine
+which section to use, you should use look at @file{/usr/info/dir} on
+your system and choose the most relevant (or create a new section if
+none of the current sections are relevant).
+
+If @file{install-info} cannot find a description entry in the Info file
+you will have to supply one.  See @file{install-info}(8) for details.
+
+@item
+If a package contains any shared libraries you will have to invoke
+@file{ldconfig} in both the @file{postinst} and @file{prerm} scripts
+to correctly update the library links.  See @file{ldconfig}(8) for
+details.
+
+@item
+Any additional documentation that comes with the package can be
+installed at the discretion of the package maintainer.  Text
+documentation should be mode 644, owned by @code{root.root}, installed
+to @file{/usr/doc}, and compressed with @file{gzip -9} unless it is small.
+
+If a subdirectory of @file{/usr/doc} is warranted, please do create one.
+Please do not install DVI, PostScript, or large textual documentation in
+the same package; upload such documentation as a separate package
+(installing its files in @file{/usr/doc}) so that it can be made
+available with the distribution.  If a user has the need for the
+documentation, they can easily get it from the archive, CD-ROM, etc.,
+but it should not take up disk space on the machines of the user who do
+not need or want it installed.
+
+@item
+Create a file named @file{/usr/doc/copyright/<@i{package}>} which gives
+details of the authorship and copyright of the package.  If the package
+is distributed under the GNU General Public Licence, the GNU Library
+General Public Licence or the Regents of the University of California at
+Berkeley (BSD) licence, please say so instead of including a copy of the
+licence.  The files @file{BSD}, @file{GPL}, and @file{LGPL} will be
+available in the @file{/usr/doc/copyright} directory for you to refer
+to.  @file{/usr/doc/copyright/<@i{package}>} should not be compressed.
+
+@emph{All} authorship and copyright information from the original source
+package must be included in the @file{/usr/doc/copyright/<@i{package}>}
+file.
+
+@item
+Any example files (for example, sample configuration files) should
+be placed in the directory @file{/usr/doc/examples}.  If the file is
+normally a hidden file, such as @file{.emacs}, then please call it
+@file{dot.emacs}, to avoid confusion.  Again, you may create a
+subdirectory if it is needed.
+
+@item
+All symbolic links should be relative, not absolute.  Absolute links,
+in general, cause problems when a file system is not mounted where it
+``normally'' resides (for example, when mounted via NFS).  In certain
+cases, however, relative links may also cause similar problems.  I
+have generally made links into @file{/etc} and @file{/var} absolute
+and all other links relative.  There may be other cases in which
+absolute links are necessary.
+
+Therefore, in the @file{Makefile} or @file{debian.rules}, do not do:
+@smallexample
+install: all
+         [...]
+         ln -fs /usr/bin/gcc /usr/bin/cc
+         [...]
+@end smallexample
+Instead, do:
+@smallexample
+ln -fs gcc /usr/bin/cc
+@end smallexample
+or
+@smallexample
+( cd /usr/bin ; ln -fs gcc cc )
+@end smallexample
+
+Please do not create hard links in the manual page directories.  In
+these cases, you should use relative symbolic links or files that
+@file{.so} (roff for `source') others instead.
+
+@item
+All command scripts should have a @code{#!} line naming the shell to be
+used to interpret them.
+
+@item
+In the case of Perl scripts this should be @code{#!/usr/bin/perl} or
+sometimes @code{#!/bin/perl}, as follows: if the script is a critical
+one that may be called when the @file{/usr} partition is unmounted or
+broken it should use @file{/bin/perl}.  Otherwise (especially if the
+script is not specifically targetted at Debian) it should use Perl's
+standard location, @file{/usr/bin/perl}.
+
+@item
+Generally the following compilation parameters should be used:
+
+@display
+   CC = gcc
+   CFLAGS = -O2 -g -Wall # sane warning options vary between programs
+   LDFLAGS = # none (or -N, if appropriate; see below)
+   install -s (or strip)
+@end display
+
+Note that all installed binaries should be stripped, either by using the
+@code{-s} flag to @file{install}, or by calling @file{strip} on the
+binaries after they have been copied into the @file{debian-tmp} but
+before the tree is made into a package.
+
+Make sure that you do not link with @code{-g}, as this makes a.out
+compilers produce huge statically linked binaries.  The @code{-g} flag
+is useful on compilation so that you have available a full set of
+debugging symbols in your built source tree, in case anyone should file
+a bug report involving (for example) a core dump.
+
+@code{-N} should only be used on binaries that are very small (less than
+8K with the @code{-N} option, roughly) and are not likely to have
+multiple instances in memory.  Do not use @code{-N} on daemons, no
+matter how small they are.
+
+It is up to the package maintainer to decide what compilation options
+are best for the package.  Certain binaries (such as
+computationally-intensive programs) may function better with certain
+flags (@code{-O3}, for example); feel free to use them.  Please use good
+judgment here.  Don't add flags for the sake of adding flags; only add
+flags if there is good reason to do so.
+
+@item
+Please make sure that you use only released versions of shared libraries
+to build your packages; otherwise other users will not be able to run
+your binaries properly.  Producing source packages that depend on
+unreleased compilers is also usually a bad idea.
+
+@item
+Logfiles should usually be named @file{/var/log/<package>}, or
+@file{/var/log/<package>.<something>} if you have several logfiles.  It
+may be appropriate to create a directory.  Make sure that any logfiles
+are rotated occasionally so that they don't grow indefinitely; the best
+way to do this is to use @file{savelog} from the cron package in an
+@file{/etc/cron.daily}, @file{/etc/cron.weekly} or
+@file{/etc/cron.monthly} script.
+
+
+@item
+Please check with the base system maintainer (Ian Murdock) before using
+users or groups other than @code{root} and others specified in this
+document.
+@end itemize
+
+
+
+@node Source Package, Binary Package, Package Content, Top
+@unnumbered Source Package
+
+   The source package should contain a file called @file{debian.rules}
+which contains at least the following targets, to be invoked in the top
+level directory:
+
+@smallexample
+build
+binary
+clean
+@end smallexample
+
+@file{debian.rules} should start with
+
+@smallexample
+#!/usr/bin/make -f
+@end smallexample
+
+@noindent and be executable.  It is a good idea to arrange for it not
+to fail obscurely when invoked in the wrong directory, for example by
+testing for the existence of a file in the source directory.
+
+@itemize @bullet
+@item
+The @file{build} target should perform all non-interactive configuration
+and compilation of the package.  If a package has an interactive
+pre-build configuration routine, the source package should be built
+@emph{after} this has taken place.
+
+   For some packages, notably ones where the same source tree is
+compiled in different ways to produce two binary packages, the
+@file{build} target does not make much sense.  For these packages it is
+good enough to provide two (or more) targets (@file{build-a} and
+@file{build-b} or whatever) for each of the ways of building the
+package, and a @file{build} target that does nothing.  The @file{binary}
+target will have to build the package in each of the possible ways and
+make the binary package out of each.
+
+@item
+The @file{binary} target of @file{debian.rules} should be all that is
+necessary for the user to build the binary package.  The binary package
+should be created using @file{dpkg} and placed in the parent of the top
+level directory.  The next section describes how to construct binary
+packages from the @file{binary} target.
+
+@item
+The @file{clean} target should undo the effects of the @file{build}
+target and the @file{binary} target, except that it should leave alone
+any @file{../<@i{package}>-<@i{version}>.deb} file created by a run of
+@file{binary}.
+
+@item
+Additional targets may exist in @file{debian.rules}.  We recommend using
+@file{source} and @file{diff} targets to build the Debianised source
+package and the Debianisation context diff, respectively.  These files
+should be placed in @file{../foo-<@i{version}>.tar.gz} and
+@file{../foo-<@i{version}>.diff.gz}.  The @file{install} target, for
+installing into a running system direct from the Debianised source
+tree, is no longer required.  The sample @file{debian.rules} provides
+@file{source} and @file{diff} targets that should work with little or
+no alteration, providing that the package-specific variables at the top
+of the script have been properly defined.
+
+@item
+If you need to edit a @file{Makefile} where @file{configure} scripts
+are used, you should edit the @file{.in} files rather than editing
+the @file{Makefile} directly.  This allows the user to reconfigure
+the package if necessary.  You should @emph{not} configure the package
+and edit the generated @file{Makefile}!  This makes it impossible for
+someone else to later reconfigure the package.
+
+@item
+Please document your changes to the source package so that future
+package maintainers know what has been changed.  To do this, include
+a description of your changes in the @file{debian.README} (which, as
+described above, should already contain authorship and copyright
+information!) and include relevant information such as your name,
+electronic mail address, date, etc.  The @file{debian.README} file
+should also document any `unusual' packages which must be installed for
+this one to compile.
+
+@item
+If changes to the source code are made that are applicable to Linux
+systems or systems in general please try to get them included in the
+upstream version of the package by supplying the upstream authors with
+the changes in whatever form they prefer.
+
+If changes to the source code are made, please use a @file{define}.  If
+they are changes required to compile or function under Linux in general,
+use @file{LINUX}.  If it is a cosmetic or functional change, use
+@file{DEBIAN}.
+
+@item
+Create the source package using @file{tar}, and use @file{gzip -9} to
+compress it.  Source packages should be named in the form
+<@i{package}>-<@i{version}>.tar.gz---for example,
+@file{fileutils-3.9-3.tar.gz}.
+
+NB, here @code{<@i{version}>} is the full Debian version number, in the
+form @code{<@i{original_version}>-<@i{debian_revision}>} (see below),
+but the tarfile should unpack into a directory named
+@code{<@i{package}>-<@i{original_version}>} (again, see the section
+below on version numbering).
+
+@item
+Create the context diff against the original package using @file{diff
+-cNr}, and use @file{gzip -9} to compress it.  Context diffs should be
+named in the form <@i{package}>-<@i{version}>.diff.gz---for example,
+@file{fileutils-3.9-3.diff.gz}.
+@end itemize
+
+   Please note that the package and patch filenames do @emph{not} need
+to fit in MS-DOS 8+3.  They will be made available under an alternative
+8+3 name in the archive by the archive maintainer, using a symlink.
+
+
+
+@node Binary Package, Control Files, Source Package, Top
+@unnumbered Binary Package
+
+   The @file{binary} target of the source package @file{debian.rules}
+file should do the following (see the sample @file{debian.rules}
+for an implementation that you are free to modify and use in your own
+packages, of course):
+
+@itemize @bullet
+@item
+Create an empty directory in the top-level directory of the source
+package (deleting it first, if necessary), and install the files
+belonging to this package in that directory.  For example, the directory
+could be called @file{debian-tmp} and would probably contain directories
+@file{debian-tmp/usr/bin}, @file{debian-tmp/usr/lib}, etc.
+(@file{debian-tmp} is the name traditionally used, and it is used in
+the sample @file{debian.rules} file, so we will use that name in the
+Guidelines.)
+
+@item
+Make sure that all the files under @file{debian-tmp} have the correct
+ownerships and permissions (@pxref{Package Content}, for more information
+about file locations, ownerships, and permissions.)
+
+@item
+Create a subdirectory of @file{debian-tmp} called @file{DEBIAN}.  This
+directory contains the package control information, including at the
+very least the master information file named @file{control}.  The next
+section describes the semantics and syntax of the files required and
+allowed here.
+
+@item
+Run @file{dpkg} to create the binary package, using something like
+
+@smallexample
+dpkg --build debian-tmp
+@end smallexample
+
+This will create a file called @file{debian-tmp.deb}, from the
+@file{debian-tmp} directory.  You should rename this file to
+@file{../<@i{package}>-<@i{version}>.deb} after it is built.
+
+After the @file{binary} target has done all this, the
+@file{<@i{package}>-<@i{version}>.deb} file in the parent directory is
+the binary distribution.  This file may be distributed and installed on
+any Debian GNU/Linux system with @file{dpkg} in the same manner and
+using the same methods as all packages are installed to the system.
+
+@item
+If a single source package corresponds to several binary packages, there
+should usually be a @file{debian.rules} file with a single @file{binary}
+target that builds all the binary packages involved and move all packages
+to the parent directory of that containing the source package.
+
+In this case, you should choose binary package names which are meant to
+make clear the close relationship between the binary packages and which
+source package the binary packages came from (for example, the
+@file{texinfo} source package build two binary packages: @file{texidoc}
+and @file{texinfo}).  You should place the appropriate binary package
+name in the @file{Package} field of the control file (not the source
+package name), and you should consider whether the other binary packages
+that come from the same source tree should be mentioned in the
+@file{Depends}, @file{Recommends} or @file{Suggests} fields.  You
+should put the source package name in the @file{Source} field.
+
+You should retain the source package version numbering in the
+@file{Version} field, if possible---the version number should be the
+same for the Debianised source tree and all the binary packages
+generated from it.  It is more important, though, that the version
+numbers sort correctly.  See below for details of version numbers.
+@end itemize
+
+
+
+@node Control Files, Appendix, Binary Package, Top
+@unnumbered Control Files
+
+   Each binary package contains, in addition to the files that comprise
+the actual package, a set of text files that control how @file{dpkg}
+installs, configures, upgrades, removes, etc. the package.  These files
+are called @dfn{control files}.  When creating the package, the control
+files should placed in a directory called @file{DEBIAN}, as described
+earlier (@pxref{Binary Package}, for further information).
+
+The control information files are:
+
+@table @code
+@item control
+The master package control information file.
+@item conffiles
+A list of package configuration files.
+@item preinst
+The package pre-installation script.
+@item postinst
+The package post-installation script.
+@item prerm
+The package pre-removal script.
+@item postrm
+The package post-removal script.
+@end table
+
+   Of these, only @file{control} is required.  The various installation
+scripts, and the configuration files list, will only be used if they are
+present.
+
+@menu
+* control::
+* conffiles::
+* Installation and Removal Scripts::
+* Dependencies and Conflicts::
+* Package Classification Fields::
+@end menu
+
+@node control, conffiles, Control Files, Control Files
+@unnumberedsec control
+
+   The @file{control} file contains a number of fields.  Each field
+begins with a field name, such as @file{Package} or @file{Version}
+(case insensitive), followed by a colon and optionally some spaces or
+tabs (a single space is conventional).  Then comes the body of the
+field, which may be several lines long; each continuation line must
+start with at least one space or tab.  (These are the same rules as
+apply to RFC822 mail headers.)  Blank lines are not permitted in the
+control file.
+
+   The required fields in the control file are the following:
+
+@table @code
+@item Package
+The name of the package.
+@item Description
+The description of the package.  How to write an extended and more
+usefull description field can be found in @pxref{How to write the Description control file field}.
+@item Maintainer
+The name and e-mail address of the maintainer of the package.
+@item Version
+The version number in the format
+@code{<@i{original_version}>-<@i{debian_revision}>}.
+@end table
+
+   Each field has a particular format and meaning for the package
+installation tools.
+
+The value of @file{Package} should be the name of the package.
+Package names must start with an alphanumeric, must be at least two
+characters, and may contain only alphanumerics and the characters
+- + . @@ : = % _ (that is, hyphen, plus, stop, at, colon, equals,
+percent and underscore).  They are not case sensitive.
+
+   The @code{Maintainer} field should be in the form
+
+@smallexample
+Joe J. Bloggs <jbloggs@@foo.com>
+@end smallexample
+
+@noindent Note that this will not be useable as an email address if
+the name given contains full stop characters, because of a silly
+restriction in the Internet mail standards.  If you want to use this
+as an email address in a program you should check for full stops and
+change the string to the form @code{jbloggs@@foo.com (Joe J. Bloggs)}
+if you find any.
+
+   The @code{Version} field should be the version number of the
+package.  For most packages which are not written specifically for
+Debian, this should be in the form
+
+@smallexample
+Version: <@i{original_version}>-<@i{debian_revision}>
+@end smallexample
+
+@noindent where @file{<@i{original_version}>} is the original package
+version number in whatever form the original package uses and
+@file{<@i{debian_revision}>} indicates which ``debianisation'' this is
+(this should usually be a plain number or perhaps a two numbers
+separated by a full stop, and should be incremented each time the
+package is changed or updated).
+
+    Packages which are written specifically for Debian do not have a
+@i{debian_revision}, and their version number should simply be
+@i{version} (which should not contain any hyphens, to avoid
+confusion).
+
+    There is an ordering imposed on version numbers, described in
+@file{version-ordering.txt}.  This ordering is designed to `do the right
+thing' in most circumstances; if your package has an version number in
+an unusual format you may need to reformat it somewhat to get the
+ordering right.  This is important because @file{dpkg} is (for example)
+reluctant to downgrade packages.
+
+   The optional fields in the control file are the following:
+
+@table @code
+@item Depends
+The names of prerequisite packages.
+@item Recommends
+The names of related, recommended packages.
+@item Suggests
+The names of related, optional packages.
+@item Conflicts
+The names of packages which conflict with this package.
+@item Provides
+The names of virtual packages which this package provides.
+@item Priority
+The `priority' of the package, as shown and used by @file{dselect}.
+@item Section
+The `section' of the package, as shown and used by @file{dselect}, and
+used as a location for the package in the distribution.
+@item Essential
+A boolean field used by the base packages.
+@item Pre-Depends
+Used by base packages to ensure that (for example) shared libraries are
+present befoore they are upgraded.
+@item Source
+Gives the name of the source package when several binary packages are
+generated from a single source tree.
+@end table
+
+@noindent See below for details of the semantics and syntax of these
+fields.  Most packages will need at least a @code{Depends} field.
+
+   An example of a @file{control} file would be:
+
+@smallexample
+Package: smail
+Version: 3.1.29.1-13
+Maintainer: Ian Jackson <iwj10@@cus.cam.ac.uk>
+Recommends: pine | mailx | elm | emacs | mail-user-agent
+Suggests: metamail
+Depends: cron, libc5
+Conflicts: sendmail
+Provides: mail-transport-agent
+Description: Electronic mail transport system.
+ Smail is the recommended mail transport agent (MTA) for Debian.
+ .
+ An MTA is the innards of the mail system - it takes messages from
+ user-friendly mailer programs and arranges for them to be delivered
+ locally or passed on to other systems as required.
+ .
+ In order to make use of it you must have one or more user level
+ mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+ and VM as mailreaders) installed.  If you wish to send messages other
+ than just to other users of your system you must also have appropriate
+ networking support, in the form of IP or UUCP.
+@end smallexample
+
+   In this case, @file{mail-user-agent} is a virtual package
+representing any user mailer program; the actual package names
+@file{pine} is quoted for the reasons described in
+@file{dependency-ordering.txt}, and the others because older versions
+of those packages do not have the appropriate @file{Provides} field.
+
+@node conffiles, Installation and Removal Scripts, control, Control Files
+@unnumberedsec conffiles
+
+   The contents of @file{conffiles} is simply a list of configuration
+files in the package.  When installing the package, @file{dpkg} uses
+an intelligent method to update these files.  This will ensure that
+package-specific configuration files are not overwritten when a package
+is upgraded, unless the user wishes the installation tools to do so.
+
+   Typically, files listed in conffiles are package-specific
+configuration files, which (according to the Linux Filesystem Standard)
+are stored in @file{/etc}.  For example, the @code{sendmail} package may
+contain the file @file{/etc/sendmail.cf}, which we do not wish to
+overwrite automatically when the user upgrades the sendmail package.
+Only those files listed in @file{DEBIAN/conffiles} will be updated
+intelligently when a package is upgraded; all other files in the package
+will be overwritten by the upgrade process.
+
+   Configuration files which will be functional as shipped and will
+probably need little or no local editing should simply be listed the
+@file{conffiles} file; in this case you need read no further.
+
+   For packages whose configuration files will need modification on
+most systems there are two sensible approaches.  Which one is chosen
+depends on how hard the configuration problem is and how much time the
+package maintainer has available.
+
+   One option is for you to ship a minimal `best-effort' file in
+@file{/etc}, and list the file in @file{conffiles}.  This will mean that
+the user will have to go and edit the file themselves to get the package
+to work properly, of course.  The next time they upgrade the package, if
+you haven't changed the file version, their old file will be left in
+place.  If you have modified your version then the user will get a
+prompt asking them which version of the file they want, theirs or yours.
+They will then usually have to resolve the discrepancies manually.
+
+   The other option is to be preferred, if you can do it: do not put a
+copy of the configuration file in the package at all.  Instead, you
+check in the postinst whether the file exists, and if it doesn't you
+prompt the user for the information you need to create a good one.  This
+is obviously harder work.
+
+  You also have to remember that you will have to keep up with your
+package's changes: if you discover a bug in the program which generates
+the configuration file, or if the format of the file changes from one
+version to the next, you will have to arrange for the postinst script to
+do something sensible---usually this will mean editing the installed
+configuration file to remove the problem or change the syntax.  You will
+have to do this very carefully, since the user may have changed the
+file, perhaps to fix the very problem that your script is trying to deal
+with---you will have to detect these situations and deal with them
+correctly.
+
+  If you do go down this route it's probably a good idea to make the
+program that generates the configuration file(s) a separate program in
+@file{/usr/sbin}, by convention called @i{package}@code{config}, and
+then run that if appropriate from the post-installation script.  The
+@i{package}@code{config} program should not unquestioningly overwrite an
+existing configuration---if its mode of operation is geared towards
+setting up a package for the first time (rather than any arbitrary
+reconfiguration later) you should have it check whether the
+configuration already exists, and require a @code{--force} flag to
+overwrite it.
+
+   @file{conffiles} should almost certainly list all the files contained
+in your package in the @file{/etc} directory.  There may also be other
+files somewhere that the user is expected to edit, which should also be
+included.  Note, however, that the FSSTND specifies that configuration
+files must be in @file{/etc}.  No Debian package should contain
+configuration files in @file{/usr/etc}, and all programs should refer to
+configuration files in @file{/etc}.
+
+@noindent For example, the TCP/IP package might use a conffiles which contains
+
+@smallexample
+/etc/init.d/netbase
+/etc/gateways
+/etc/protocols
+/etc/services
+/etc/hosts.allow
+/etc/hosts.deny
+/etc/rpc
+@end smallexample
+
+@noindent and so on; the files
+
+@smallexample
+/etc/hosts
+/etc/inetd.conf
+/etc/host.conf
+/etc/networks
+/etc/resolv.conf
+@end smallexample
+
+@noindent might be generated by an interactive configuration program,
+and would then not be included in the package or listed in the
+@file{conffiles}.
+
+@node Installation and Removal Scripts, Dependencies and Conflicts, conffiles, Control Files
+@unnumberedsec Installation and Removal Scripts
+
+   The scripts @file{preinst}, @file{postinst}, @file{prerm}, and
+@file{postrm} are optional (Bash or Perl) scripts.  As the names
+would indicate, if these scripts exist, they will be executed before
+installing the package, after installation, before package removal,
+and after removal, respectively.
+
+   They are given arguments which indicate the precise situation and
+action being performed---see @file{maintainer-script-args.txt} for
+details of exactly when each of the scripts is invoked and what its
+arguments are.  Extra arguments and situations may be added later, so
+you should not test the number of arguments to your script to determine
+the situation, and you should choose the sense of your `if it is this
+then do this otherwise do that' tests carefully.
+
+   These scripts can be used to perform any site-specific package
+configuration.
+
+   Because the scripts will be exectued by the dpkg front-end, it is
+guaranteed that the scripts will be executed interactively.  User input
+from the scripts should be read from standard input, not the user's
+terminal.  Similarly, output should be sent to standard output.
+
+   If your maintainer scripts need to prompt for passwords and/or do
+@i{full-screen} interaction should do these things to and from
+@file{/dev/tty}, since @file{dpkg} will at some point redirect scripts'
+standard input and output so that it can log the installation process.
+Likewise, because these scripts may be executed with standard output
+redirected into a pipe for logging purposes, Perl scripts should set
+unbuffered output by setting @code{$|=1} so that the output is printed
+immediately rather than being buffered.
+
+   The scripts must be idempotent, and they must clean up after
+themselves properly.  Ie, they must do the right thing if run multiple
+times, even if previous runs failed halfway through.  This is so that if
+any errors occur, or if the @file{dpkg} run is interrupted, the user can
+recover by rerunning @file{dpkg}, and/or by upgrading to a new version
+and then rerunning the failed operation.
+
+   These scripts should avoid producing output which it is unnecessary
+for the user to see and should rely on @file{dpkg} to stave off boredom
+on the part of a user installing many packages.  This means, amongst
+other things, using the @file{--quiet} option on @file{install-info}.
+
+   Packages should try to minimise the amount of prompting they need to
+do, and they should ensure that the user will only every be asked each
+question once.  This means that packages should try to use appropriate
+shared configuration files (such as @file{/etc/papersize} and
+@file{/etc/news/server}), rather than each prompting for their own list
+of required pieces of information.
+
+   It also means that an upgrade should not ask the same questions
+again, unless the user has used @code{dpkg --purge} to remove the
+package's configuration.  The answers to configuration questions should
+be stored in an appropriate place in @file{/etc} so that the user can
+modify them, and how this has been done should be documented.
+
+   If a package has a vitally important piece of information to pass to
+the user (such as "don't run me as I am, you must edit the following
+configuration files first or you risk your system emitting
+badly-formatted messages"), it should display this in the
+@file{postinst} script and prompt the user to hit Return to acknowledge
+the message.  Copyright messages do not count as vitally important (they
+belong in @file{/usr/doc/copyright}; neither do instructions on how to
+use a program (these should be in on line documentation, where all the
+users can see them).
+
+   They should return a zero exit status for success, or a nonzero one
+for failure.  Note that if a script is a @code{#!/bin/sh} script it
+should probably start with @code{set -e}, to avoid continuing after
+errors---see @file{bash}(1) for details.  Perl scripts should check for
+errors when making calls such as @code{open}, @code{print},
+@code{close}, @code{rename} and @code{system}.
+
+   If these scripts exist they should be left in the @file{DEBIAN}
+directory with execute permission enabled and should contain an
+appropriate @code{#!} line, such as @code{#!/bin/bash} for a
+@code{bash} script or @code{#!/bin/perl} for a Perl script (see
+above).
+
+@node Dependencies and Conflicts, Package Classification Fields, Installation and Removal Scripts, Control Files
+@unnumberedsec Conflicts, Depends, Suggests, Recommends and Provides
+
+   The @file{Depends} field lists packages that are required for this
+package to provide a significant amount of functionality.  The package
+maintenance software will not allow a package to be installed without
+also installing packages listed in its @code{Depends} field, and will
+run the @code{postinst} scripts of packages listed in @code{Depends}
+fields before those of the packages which depend on them, and run the
+@code{prerm} scripts before.
+
+   Packages containing dynamically-linked executable binaries (this
+includes almost all C programs) should include a @file{Depends} field
+which mentions the shared C library required for the program to run.
+For a.out binaries linked against @file{libc.so.4} the relevant package
+name is @file{libc} (for the a.out stable 0.93 tree) or @file{libc4}
+(for the unstable development 1.1 tree); for ELF binaries linked against
+@file{libc.so.5} the relevant package name is @file{libc5}.
+
+   The @code{Recommends} field lists packages that would be found
+together with this one in all but unusual installations.  The user-level
+package maintenance program @file{dselect} will warn the user if they
+select a package without those listed in its @code{Recommends} field.
+Note that @code{Recommends} fields do not currently have any implications
+for the order in which the maintainer scripts are run.
+
+   The @code{Suggests} field lists packages that are related to this one
+and can perhaps enhance its usefulness, but without which installing
+this package is perfectly reasonable.  The package maintenance software
+will not moan at the user for not selecting @code{Suggests} related
+packages, but may use the information in the @code{Suggests} field to
+assist the user during package selection.
+
+   The syntax of @code{Depends}, @code{Recommends} and @code{Suggests}
+is a list of groups of alternative packages.  Each group is a list of
+packages separated by vertical bar (or `pipe') symbols, @code{|}.  The
+groups are separated by commas.  Each package is a package name
+optionally followed by a version number specification in parentheses.  A
+version number may start with a @code{>=}, in which case that version or
+any later will match, or @code{<=} for that version or any earlier
+version. A version number starting with a @code{>>} or @code{<<} will
+respectively match any later or earlier version. If a version number or
+a version number starting with @code{=} is specified an exact match is
+required. Commas are to be read as `AND', and pipes as `OR', with pipes
+binding more tightly.
+
+   Versions of dpkg before 1.0.9 used @code{<} and @code{>} for
+@code{<=} and @code{>=} (these are still supported for backward
+compatibility), and did not support @code{<<} and @code{>>}.
+
+   The @code{Conflicts} field lists packages that conflict with this
+one, for example by containing files with the same names (an example
+would be Smail vs. Sendmail).  The package maintenance software will not
+allow conflicting packages to be installed.  Two conflicting packages
+should each include a @code{Conflicts} line mentioning the other.
+
+   The syntax of @code{Conflicts} is a list of package names (with
+optional version numbers), separated by commas (and optional
+whitespace).  In the @code{Conflicts} field the comma should be read as
+`OR'.
+
+   The @code{Provides} field lists the names of any `virtual packages'
+of which this packages is to be considered an instantiation.  Virtual
+packages are used to allow packages to refer to a service they require
+(such as the availability of @file{/usr/sbin/sendmail}) without having
+to know the names of all the relevant packages.  The virtual package
+names defined in @code{Provides} fields may be used in other packages'
+@code{Depends}, @code{Recommends}, @code{Suggests} and @code{Conflicts}
+fields.  For more information about how to use virtual packages and
+which virtual package names to use read @pxref{Virtual dependencies} and
+@file{doc/package-developer/virtual-package-names-list.text}.
+
+   The syntax of @code{Provides} is a list of package names separated by
+commas (and optional whitespace).
+
+@node Package Classification Fields,  , Dependencies and Conflicts, Control Files
+@unnumberedsec Priority, Section and Essential
+
+   The @code{Priority} and @code{Section} fields are used by
+@file{dselect} when displaying the list of packages to the user.  There
+is no need to put them into a package, since these are usually set by
+the distribution maintainers in the @file{Packages} file.
+
+   However, if a user installs a package which is not part of the
+standard distribution, or without downloading and updating from a new
+@file{Packages} file, the information about the priority and section of
+a package will be absent, and the @file{dselect} package listing will
+have the package listed under `unclassified'.  It is permissible for a
+package to include @code{Section} or @code{Priority} fields to improve
+this; however, if you do this you should make sure you keep the
+information up to date so that users are not shown conflicting
+information.  The @code{Section} field can also be used by the
+distribution maintainers as a suggestion about which section you think
+is most appropriate for your package.
+
+  The values for the @code{Section} and @code{Priority} fields should be
+determined by the distribution maintainers; if you don't know what to
+put in them just leave them out.  You can add them later, if you like,
+but remember that you'll then have to reissue your package if the
+distribution maintainers change the classification of your package.
+
+  The @code{Essential} field should only appear in packages in the
+installation's base system.  If it is set to @code{yes} then @file{dpkg}
+will not remove the package even if asked to, and will make certain
+minor modifications to its installation procedures.  The only other
+legal value is @code{no}, which is equivalent to the absence of the
+field.
+
+@appendix
+@node Appendix,  , Control Files, Top
+@unnumbered Appendix
+@comment  node-name,  next,  previous,  up
+@menu
+* configuration files -- /etc/skel vs /usr/doc/examples::
+* How to write the Description control file field::
+* Configuration of init::
+* Maintainer script arguments and how @file{dpkg} does things::
+* Mail processing packages::
+* Virtual dependencies::
+@end menu
+
+@node configuration files -- /etc/skel vs /usr/doc/examples, How to write the Description control file field, Appendix, Appendix
+@comment  node-name,  next,  previous,  up
+@unnumberedsec configuration files -- /etc/skel vs /usr/doc/examples
+
+There seems to be a certain amount of confusion about @file{/etc/skel}
+and @file{/usr/doc/examples}. The most important thing to remember is
+the following:
+
+Files in @file{/etc/skel} will @emph{automatically} be copied into
+@emph{new} user accounts by @file{adduser}.  They should not
+be referenced there by any program. Files in @file{/usr/doc/examples}
+should not be installed automatically.
+
+Therefore, if the program in question need a dotfile to exist in advance
+in @file{$HOME} to work @emph{sensibly} that dotfile should be installed
+in @file{/etc/skel} (and listed in conffiles; @pxref{conffiles}).
+
+However, programs that require dotfiles in order to operate sensibly
+(dotfiles that they do not create themselves automatically, that is) are
+a bad thing, and that programs should be configured by the Debian
+default installation as close to normal as possible.
+
+Therefore, if a program in a Debian package needs to be configured in
+some way in order to operate sensibly that configuration should be done
+in a site-wide global configuration file elsewhere in @file{/etc} (and
+that file should be listed in conffiles).  Only if the program doesn't
+support a site-wide default configuration should a default per-user file
+be placed in @file{/etc/skel} (and listed in conffiles;
+@pxref{conffiles}).
+
+The idea is as follows:
+
+The sysadmin should ideally not have to do any configuration other than
+that done @w{(semi-)}automatically by the postinst script.
+
+However, if they wish to change their configuration themselves
+(because the configuration they want is beyond the scope of the
+autoconfiguration, or because the autoconfiguration doesn't exist yet,
+or because they just want to do it themselves for any reason) then
+@file{/usr/doc/examples} exists as @emph{documentation} for their benefit.
+
+The only time these files should be read are by the sysadmin using their
+favourite editor or pager, or @emph{perhaps} (in very complex packages)
+by the postinst as a template to build on or modify.
+
+@file{/etc/skel} is part of the @emph{implementation} of this
+configuration.  It contains the files that are copied into new user
+accounts.  It should probably be as empty as we can make it.
+
+Examples:
+@table @code
+@item .profile
+@file{/etc/skel} should not contain a @file{.profile} file.  Anything
+that needs to be done there should be done in @file{/etc/profile}.
+Anything that should not go in @file{/etc/profile} (users can't avoid
+running @file{/etc/profile}) probably should not be in the default
+configuration.  bash has generally good default behaviour.
+
+@item .bash_logout
+Likewise, bash functions perfectly happily without a
+@file{.bash_logout}, so none should be provided, since anything in it is
+a deviation from the sensible default behaviour.
+
+@item .xsession
+@file{/etc/skel} should not contain a @file{.xsession}.  @file{xdm}'s
+system-wide startup file @file{/usr/lib/X11/xdm/Xsession} supports a
+system-wide default user configuration (which should probably be
+@file{/etc/X11/Xsession} or some such) which may be overridden by
+@file{.xsession} in the user's home directory.  Therefore there is no
+need for a @file{.xsession} to be installed by default and none should
+be provided.
+
+Instead, a sensible @file{/etc/X11/Xsession} should be provided, and if
+desired this can be used as a template by users who wish to install
+their own configuration, or alternatively a more comprehensive example
+with much commented-out interesting stuff could be put in
+@file{/usr/doc/examples}.
+
+If the sysadmin wishes to change the system-wide default they should
+probably do this by editing @file{/etc/X11/Xsession} rather than
+creating the file in @file{/etc/skel}, because the former will affect
+all user accounts that haven't explicitly overridden things by creating
+their own file while the latter will only affect new accounts.
+
+All the configuration necessary for a program to function should be
+provided.  Therefore sysadmins will not need to go through
+@file{/usr/doc/examples} while editing configuration files in
+@file{/etc} except in extreme cases (like INN) where the configuration
+was too difficult to do automatically.
+
+@item site-wide defaults
+Site-wide defaults should not go in @file{/etc/skel}.  In the case of
+twm, for example, the system-wide default should be in
+@file{/etc/X11/system.twmrc}.  (The default location for this in X11R5,
+btw, is in @file{/usr/lib/X11} somewhere, but we can't put it on
+@file{/usr} because of CDROM distributions, etc - hence the FSSTND's
+mandate to put configuration files in @file{/etc}.)
+
+@item .twmrc
+There should be no @file{.twmrc} file in @file{/etc/skel}.  You can have
+one in @file{/usr/doc/examples} if you @emph{like}, but why bother if
+@file{system.twmrc} is a good example (and indeed is the one the user is
+using before they create their own)?
+
+@item m4
+@file{/usr/doc/examples} isn't mainly for example @emph{configuration
+files}.  It's for any kind of example file distributed with a package.
+For example, GNU m4 comes with a whole pile of example m4 macro scripts,
+which is exactly what @file{/usr/doc/examples} is for.
+@end table
+
+Summary
+
+Files that should be installed in new user accounts should be in
+@file{/etc/skel}, as that will ensure that they @emph{are} installed in
+new user accounts!  However, we should try to avoid the need for this.
+
+@file{/usr/doc/examples} is just what it says: documentation in the form
+of examples.  If a sysadmin is required to go and read these files for
+their system to work they should be told about it.  For example, here
+is what the Smail postinst script says right at the start:
+
+@smallexample
+I can do certain kinds of automatic configuration of your
+mail system, by asking you a number of questions.  Later you
+may to confirm and/or correct your answers.  In any case,
+comprehensive information on configuring Smail is in
+smail(5) and in /usr/doc/examples/smail and
+/usr/doc/smail-admin-guide.
+@end smallexample
+
+@node How to write the Description control file field, Configuration of init, configuration files -- /etc/skel vs /usr/doc/examples, Appendix
+@unnumberedsec How to write the Description control file field
+
+The format of the @code{Description} field is as follows:
+
+@smallexample
+Description: <single line synopsis>
+ <extended description over several lines>
+@end smallexample
+
+The extended description has several kinds of line:
+
+@itemize @bullet
+@item
+Those starting with a single space are part of a paragraph.  Successive
+lines of this form will be word-wrapped when displayed.  The leading
+space will usually be stripped off.
+
+@item
+Those starting with two or more spaces.  These will be displayed
+verbatim.  If the display cannot be panned horizontally the displaying
+program will linewrap them `hard' (ie, without taking account of word
+breaks).  If it can they will be allowed to trail off to the right.
+None, one or two initial spaces may be deleted, but the number of spaces
+deleted from each line will be the same (so that you can have indenting
+work correctly, for example).
+
+@item
+Those containing a single space followed by a single full stop
+character.  These are rendered as blank lines.  This is the @emph{only}
+way to get a blank line - see below.
+
+@item
+Those containing a space, a full stop and some more characters.  These
+are for future expansion.  @emph{Do not} use them.
+@end itemize
+
+IMPORTANT and not so important TIPS:
+
+@itemize @bullet
+@item
+@emph{Always} start extended description lines with at least @emph{one}
+whitespace character.  Fields in the control file and in the Packages
+file are separated by field names starting in the first column, just as
+in RFC822.  Forgetting the whitespace will cause @file{dpkg-deb}
+(>=0.93.23) to produce a syntax error when trying to build the package.
+If you force it to build anyway @file{dpkg} will refuse to install the
+resulting mess.
+
+@item
+@emph{Do not} include any completely @emph{empty} lines. These separate
+different records in the Packages file, and are forbidden in control
+files.  See the previous paragraph for what happens if you get this
+wrong.
+
+@item
+The single line synopsis should be kept brief - certainly under 80
+characters.  @file{dselect} displays the @emph{first 49} characters if
+you're using an 80-column terminal.
+
+@item
+Do not include the package name in the synopsis line.  The display
+software knows how to display this already, and you do not need to
+state it.  Remember that in many situations the user may only see the
+synopsis line - make it as informative as you can.
+
+@item
+The extended description should describe what the package does and how
+it relates to the rest of the system (in terms of, for example, which
+subsystem it is which part of).
+
+@item
+Put important information first, both in the synopis and extended
+description.  Sometimes only the first part of the synopsis or of the
+description will be displayed.  You can assume that there will usually
+be a way to see the whole extended description.
+
+@item
+You may include information about dependencies and so forth in the
+extended description, if you wish.
+
+@item
+Do not use tab characters.  Their effect is not predictable.
+@end itemize
+
+Example control file for Smail:
+
+@smallexample
+Package: smail
+Version: 3.1.29.1-13
+Maintainer: Ian Jackson <iwj10@@cus.cam.ac.uk>
+Recommends: pine | mailx | elm | emacs | mail-user-agent
+Suggests: metamail
+Depends: cron, libc5
+Conflicts: sendmail
+Provides: mail-transport-agent
+Description: Electronic mail transport system.
+ Smail is the recommended mail transport agent (MTA) for Debian.
+ .
+ An MTA is the innards of the mail system - it takes messages from
+ user-friendly mailer programs and arranges for them to be delivered
+ locally or passed on to other systems as required.
+ .
+ In order to make use of it you must have one or more user level
+ mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+ and VM as mailreaders) installed.  If you wish to send messages other
+ than just to other users of your system you must also have appropriate
+ networking support, in the form of IP or UUCP.
+@end smallexample
+
+@node Configuration of init, Maintainer script arguments and how @file{dpkg} does things, How to write the Description control file field, Appendix
+@unnumberedsec Configuration of init
+
+The @file{/etc/init.d} directory contains the scripts executed by
+init(8) when init state (or "runlevel") is changed.  This includes the
+boot process, when the multi-user state begins.  Several of these
+scripts are included with init and are intended to be executed
+@emph{once}, usually at boot time.  An example is
+@file{/etc/init.d/boot}, which is executed at boot time to check and
+mount file systems, activate swap, load kernel modules, etc.--everything
+that needs to be done before the multi-user state begins.
+@file{/etc/init.d} also contains the scripts that are executed when
+entering runlevel 0 (halt), runlevel 1 (single-user) and runlevel 6
+(reboot).
+
+Packages can (and should) place scripts in @file{/etc/init.d} to start
+or stop services at boot time or during a change of runlevel.  These
+scripts should be named @file{/etc/init.d/}<package>, and they should
+accept one of two arguments: "start", which starts the services, or
+"stop", which stops the services.  These scripts should ensure that they
+will behave sensibly if invoked with "start" when the service is already
+running, or with "stop2 when it isn't---the best way to achieve this is
+often to use @file{start-stop-daemon}.
+
+This script should not fail obscurely when the configuration files
+remain but the package has been removed, as the default in dpkg is to
+leave configuration files on the system after the package has been
+removed.  Only when it is executed with the `--purge' option will dpkg
+remove configuration files.  Therefore, you should include a `test'
+statement at the top of the script, like this:
+
+@smallexample
+test -f <program-executed-later-in-script> || exit 0
+@end smallexample
+
+These scripts should be referenced, when appropriate, by symbolic links
+in the @file{/etc/rc?.d} directories, as below.
+
+When changing runlevels, init looks in the directory @file{/etc/rc<n>.d}
+for the scripts it should execute, where <n> is the runlevel that is
+being changed to.  Please note that the "scripts" in @file{/etc/rc?.d}
+are not actually scripts; they are symbolic links, referencing actual
+scripts in @file{/etc/init.d}.  For simplicity, we refer to them as
+"scripts".
+
+First, the scripts prefixed with a "K" are executed, followed by the
+scripts prefixed with an "S".  The "K" scripts are responsible for
+killing certain services and the "S" scripts for starting certain
+services upon @emph{entering} the runlevel.  For example, if we are
+changing from runlevel 2 to runlevel 3, init will first execute all of
+the "K" prefixed scripts it finds in @file{/etc/rc3.d} (to kill
+services), and then all of the "S" prefixed scripts it finds in
+@file{/etc/rc3.d} (to start services).  The "K" scripts will execute the
+file it references with an argument of "stop", and the "S" scripts will
+execute this file with an argument of "start".
+
+After the "K" or "S" prefix, there should be a number specified, and
+this number should be between 00 and 99.  The number determines the
+order in which the scripts are run.  For example, the "K20" scripts will
+be executed before the "K30" scripts.  You can use this number to make
+sure that a certain service is started before another.  For example, on
+some machines, the program @file{setserial} may need to properly set an
+IRQ before the @file{ppp} program uses a modem to connect to a network.
+In this case, the script that runs @file{setserial} should have a lower
+number than the script that starts @file{ppp} so that it runs first:
+
+@smallexample
+@file{/etc/rc2.d/S10setserial}
+@file{/etc/rc2.d/S20ppp}
+@end smallexample
+
+If it does not matter when or in which order the script is run, use the
+number "20".  If it does, then you should talk to the maintainer of the
+@code{sysvinit} package or post to @code{debian-devel}, and they will
+help you choose a number.
+
+In Debian GNU/Linux, we try to ship our software in as much of a
+"default" state as possible.  Therefore, unless there is a good reason
+for doing differently, we ask that you start and stop the services in
+each of the multi-user state runlevels (2, 3, 4, and 5).  If a service
+needs to be stopped before a file system can be unmounted (an example is
+process accounting or quota services), then be sure to stop them in the
+halt runlevel (0), the single-user runlevel (1) and the reboot runlevel
+(6).
+
+The system administrator will have the opportunity to customize
+runlevels by simply adding, moving, or removing the symbolic links in
+@file{/etc/rc?.d}.  This is why we default to running everything in the
+multi-user state--a reasonable default--and the administrator can easily
+customize init to be as complex and sophisticated as he or she wants it
+to be beyond this.
+
+We provide a script, @file{update-rc.d}, to make it easier for package
+maintainers to arrange for the proper creation and removal of
+@file{/etc/rc?.d} symbolic links from their postinst and postrm scripts.
+You should use this script to make changes to @file{/etc/rc?.d} and
+@emph{never} include any @file{/etc/rc.?.d} symbolic links in the actual
+archive.
+
+@itemize @bullet
+@item
+In the postinst script, you need only do the following to setup
+@file{/etc/rc?.d}.  You should redirect standard output to
+@file{/dev/null}, as @file{update-rc.d} produces insignificant output:
+
+@smallexample
+update-rc.d <package> default >/dev/null
+@end smallexample
+
+where <package> is the name of the file as it appears in
+@file{/etc/init.d}.  It will use the default number of "20", as
+mentioned above.  If you need to use a different number, you can specify
+it after "default":
+
+@smallexample
+update-rc.d <package> default 30 >/dev/null
+@end smallexample
+
+@item
+In the postrm script, you need only do the following @emph{if and only
+if} it is called with the `purge' argument:
+
+@smallexample
+if [ purge = "$1" ]
+then
+  update-rc.d <package> remove >/dev/null
+fi
+@end smallexample
+@end itemize
+
+@unnumberedsubsec Important Note:
+
+@emph{Do not} include the @file{/etc/rc?.d/*} symbolic links in the
+archive!  @emph{This will cause problems!}  You should create them with
+update-rc.d, as above.
+
+@emph{Do not} include the @file{/etc/rc?.d/*} symbolic links in
+conffiles!  @emph{This will cause problems!}  @emph{Do}, however,
+include the @file{/etc/init.d} scripts in conffiles.
+
+
+@unnumberedsubsec Example:
+
+The process accounting package wants to make sure that process
+accounting is started at boot time and that it is stopped before the
+system is halted, enters the single-user state, or is rebooted (so
+that the @file{/var} file system can be properly unmounted).  It puts
+a script that does this in @file{/etc/init.d}, naming the script
+appropriately "acct".  This script accepts one of two arguments:
+either "start", which starts process accounting, or "stop", which
+stops it.  To ensure that it does not fail obscurely when the
+configuration files remain but the package has been removed, we
+include a `test' statement at the top of the script:
+
+@smallexample
+#! /bin/sh
+#
+# Start process accounting.
+. /etc/init.d/functions
+test -f /usr/sbin/accton || exit 0
+case "$1" in
+  start)
+    echo "Starting process accounting"
+    /usr/sbin/accton /var/account/pacct
+    ;;
+  stop)
+    echo "Stopping process accounting"
+    /usr/sbin/accton
+    ;;
+  *)
+    echo "Usage: /etc/init.d/acct @{start|stop@}"
+    exit 1
+esac
+exit 0
+@end smallexample
+
+You may find a skeletal script from which to base your @file{/etc/init.d}
+scripts in @file{/etc/init.d/skeleton}.
+
+We want to stop then (re)start process accounting when entering a
+multi-user state--runlevels 2, 3, 4, and 5--and we want to stop it when
+leaving such a state--runlevels 0 (halt), 1 (single) and 6 (reboot).
+These are good defaults, and we accomplish this by including the
+following in the postinst:
+
+@smallexample
+update-rc.d acct default >/dev/null
+@end smallexample
+
+When the user removes the acct packages with the `--purge' option, we
+want to make sure the @file{/etc/rc?.d} symbolic links are properly
+removed, so we include the following in the postrm:
+
+@smallexample
+update-rc.d acct remove >/dev/null
+@end smallexample
+
+Otherwise, the @file{/etc/rc?.d} symbolic links will remain on the system
+along with @file{/etc/init.d/acct} script.
+
+@node Maintainer script arguments and how @file{dpkg} does things, Mail processing packages, Configuration of init, Appendix
+@unnumberedsec Maintainer script arguments and how @file{dpkg} does things
+
+This appendix describes exactly how maintainer scripts are called, with
+what arguments, in what order, and what @file{dpkg} does in between.
+
+In all cases version numbers are <version>-<revision>, if the package
+has both, or just <version>.  @code{upgrade} is used even when the new
+version number looks lower than the old.
+
+
+@unnumberedsubsec Summary
+
+@smallexample
+<new preinst> install
+<new preinst> install <old-version>
+<new preinst> upgrade <old-version>
+<old preinst> abort-upgrade <new-version>
+
+<postinst> configure
+<old postinst> abort-upgrade <new version>
+<conflictor's postinst> abort-remove in-favour <package> <new version>
+<deconfigured's postinst> abort-deconfigure \
+              in-favour <package-being-installed-but-failed> <version>
+              removing <conflicting-package> <version>
+
+<prerm> remove
+<old prerm> upgrade <new version>
+<new prerm> failed-upgrade <old-vppersion>
+<conflictor's prerm> remove in-favour <package> <new version>
+<deconfigured's prerm> deconfigure \
+              in-favour <package-being-installed> <version> \
+              removing <conflicting-package> <version>
+
+<postrm> remove
+<postrm> purge
+<old postrm> upgrade <new-version>
+<new postrm> failed-upgrade <old-version>
+<new postrm> abort-install
+<new postrm> abort-install <old-version>
+<new postrm> abort-upgrade <old-version>
+<disappearer's postrm> disappear <overwriter> <new version>
+@end smallexample
+
+
+@unnumberedsubsec Details of unpack phase of installation or upgrade
+
+The procedure on installation/upgrade/overwrite/disappear (ie, when
+running @code{dpkg --unpack}, or the unpack stage of @code{dpkg
+--install}) is as follows.  In each case if an error occurs the actions
+in are general run backwards - this means that the maintainer scripts
+are run with different arguments in reverse order.  These are the `error
+unwind' calls listed below.
+
+@enumerate
+@item
+@noindent @enumerate a
+@item
+If a version the package is already
+installed, call
+@smallexample
+<old prerm> upgrade <new version>
+@end smallexample
+@item
+If this gives an error (ie, a non-zero exit status), dpkg will
+attempt instead:
+@smallexample
+<new prerm> failed-upgrade <old-version>
+@end smallexample
+@noindent error unwind, for both the above cases:
+@smallexample
+<old postinst> abort-upgrade <new version>
+@end smallexample
+@end enumerate
+@item
+If a `conflicting' package is being removed at the same time:
+@noindent @enumerate a
+@item
+If any packages depended on that conflicting package and
+@code{--auto-deconfigure} is specified, call, for each such package:
+@smallexample
+<deconfigured's prerm> deconfigure \
+ in-favour <package-being-installed> <version> \
+ removing <conflicting-package> <version>
+@end smallexample
+@noindent error unwind:
+@smallexample
+<deconfigured's postinst> abort-deconfigure \
+ in-favour <package-being-installed-but-failed> <version>
+ removing <conflicting-package> <version>
+@end smallexample
+The deconfigured packages are marked as requiring configuration, so
+that if --install is used they will be configured again if possible.
+@item
+To prepare for removal of the conflicting package, call:
+@smallexample
+<conflictor's prerm> remove in-favour <package> <new version>
+@end smallexample
+@noindent error unwind:
+@smallexample
+<conflictor's postinst> abort-remove in-favour <package> <new version>
+@end smallexample
+@end enumerate
+@item
+@noindent @enumerate a
+@item
+If the package is being upgraded, call
+@smallexample
+<new preinst> upgrade <old-version>
+@end smallexample
+@item
+otherwise, if the package had some configuration files from a previous
+version installed (ie, it is in the conffiles-only state):
+@smallexample
+<new preinst> install <old-version>
+@end smallexample
+@item
+otherwise (ie, the package was completely purged):
+@smallexample
+<new preinst> install
+@end smallexample
+@noindent error unwind versions, respectively:
+@smallexample
+<new postrm> abort-upgrade <old-version>
+<new postrm> abort-install <old-version>
+<new postrm> abort-install
+@end smallexample
+@end enumerate
+@item
+The new package's files are unpacked, overwriting any that may be on the
+system already, for example any from the old package or from another
+package (backups of the old files are left around, and if anything goes
+wrong dpkg will attempt to put them back as part of the error unwind).
+@item
+@noindent @enumerate a
+@item
+If the package is being upgraded, call
+@smallexample
+<old postrm> upgrade <new-version>
+@end smallexample
+@item
+If this fails, dpkg will attempt:
+@smallexample
+<new postrm> failed-upgrade <old-version>
+@end smallexample
+@noindent error unwind, for both cases:
+@smallexample
+<old preinst> abort-upgrade <new-version>
+@end smallexample
+@end enumerate
+This is the point of no return - if dpkg gets this far, it won't back
+off past this point if an error occurs.  This will leave the package in
+a fairly bad state, which will require a successful reinstallation to
+clear up, but it's when dpkg starts doing things that are irreversible.
+@item
+Any files which were in the old version of the package but not in the
+new are removed.
+@item
+The new file list replaces the old.
+@item
+The new maintainer scripts replace the old.
+@item
+Any packages all of whose files have been overwritten during the
+installation, and which aren't required for dependencies, are considered
+to have been removed.  For each such package,
+@noindent @enumerate a
+@item
+dpkg calls:
+@smallexample
+<disappearer's postrm> disappear <overwriter> <new version>
+@end smallexample
+@item
+The package's maintainer scripts are removed.
+@item
+It is noted in the status database as being in a sane state, namely not
+installed (any conffiles it may have are ignored).  Note that
+disappearing packages do not have their prerm called, because dpkg
+doesn't know in advance that the package is going to vanish.
+@end enumerate
+@item
+Any files in the package we're unpacking that are also listed in the
+file lists of other packages are removed from those lists.  (This will
+lobotomise the file list of the `conflicting' package if there is one.)
+@item
+The backup files made at 4. are deleted.
+@item
+The new package's status is now sane, and recorded as `unpacked'.  Here
+is another point of no return - if the conflicting package's removal
+fails we do not unwind the rest of the installation; the conflicting
+package is left in a half-removed limbo.
+@item
+If there was a conflicting package we go and do the removal actions,
+starting from point 2. of the removal, below.
+@end enumerate
+
+
+@unnumberedsubsec Details of configuration
+
+When we configure a package (this happens with @code{dpkg --install}, or with
+@code{--configure}), we first update the conffiles and then call:
+@smallexample
+<postinst> configure <most-recently-configured-version>
+@end smallexample
+
+No attempt is made to unwind after errors during configuration.
+
+
+@unnumberedsubsec Details of removal and/or configration purging
+
+@enumerate
+@item
+@smallexample
+<prerm> remove
+@end smallexample
+@item
+The package's files are removed (except conffiles).
+@item
+@smallexample
+<postrm> remove
+@end smallexample
+@item
+All the maintainer scripts except the postrm are removed.
+
+If we aren't purging the package we stop here.  Note that packages which
+have no postrm and no conffiles are automatically purged when removed,
+as there is no difference except for the dpkg status.
+
+@item
+The conffiles and any backup files (@samp{~}-files, @samp{#*#} files,
+@samp{%}-files, .dpkg-@{old,new,tmp@}, etc.) are removed.
+@item
+@smallexample
+<postrm> purge
+@end smallexample
+@item
+The package's file list is removed.
+@end enumerate
+No attempt is made to unwind after errors during removal.
+
+@node Mail processing packages, Virtual dependencies, Maintainer script arguments and how @file{dpkg} does things, Appendix
+@unnumberedsec Mail processing packages
+
+Debian packages which process electronic mail (whether mail-user-agents
+(MUA) or alternative mail-transport-agents (MTA)) @emph{must} make sure
+that they are compatible with the configuration decisions below.
+Failure to do this may result in lost mail, broken @code{From:} lines,
+and other serious brain damage!
+
+@itemize @bullet
+@item
+The mail spool is @file{/var/spool/mail} and the interface to send a
+mail message is @file{/usr/sbin/sendmail} (as per the FSSTND).  The mail
+spool is part of the base and not part of the MTA package.
+
+@item
+Mailboxes are locked using the @file{.lock} lockfile convention, rather
+than fcntl, flock or lockf.
+
+@item
+Mailboxes are generally 660 @file{<user>.mail} unless the user has
+chosen otherwise.  A MUA may remove a mailbox (unless it has nonstandard
+permissions) in which case the MTA or another MUA must recreate it if
+needed.  Mailboxes must be writeable by group mail.
+
+@item
+The mail spool is 2775 mail.mail, and MUA's need to be setgid mail to do
+the locking mentioned above (and obviously need to avoid accessing other
+users' mailboxes using this privilege).
+
+@item
+@file{/etc/aliases} is the source file for the system mail aliases (e.g.
+postmaster, usenet, etc.) - it is the one which the sysadmin and
+postinst scripts may edit.
+
+@item
+The convention of writing `forward to <address>' in the mailbox itself
+is not supported.  Use a @file{.forward} file instead.
+
+@item
+The location for the @file{rmail} program used by UUCP for incoming mail
+is @file{/usr/sbin/rmail}, as per the FSSTND.  Likewise, @file{rsmtp},
+for receiving batch-SMTP-over-UUCP, is in @file{/usr/sbin/rsmtp} if it
+is supported.
+
+@item
+Smail is not using HoneyDanBer UUCP, whose uux apparently accepts -a and
+-g options.
+
+@item
+If you need to know what name to use (for example) on outgoing news and
+mail messages which are generated locally, you should use the file
+@file{/etc/mailname}.  It will contain the portion after the username
+and @samp{@@} sign for email addresses of users on the machine (followed
+by a newline).
+@end itemize
+
+A package should check for the existence of this file.  If it exists it
+should use it without comment @footnote{An MTA's prompting configuration
+script may wish to prompt the user even if it finds this file exists.}.
+If it does not exist it should prompt the user for the value and store
+it in @file{/etc/mailname} as well as using it in the package's
+configuration.  The prompt should make it clear that the name will not
+just be used by that package.  E.g., in the same situation the INN
+package says:
+
+@smallexample
+Please enter the `mail name' of your system.  This is the hostname
+portion of the address to be shown on outgoing news and mail messages.
+The default is `$syshostname', your system's host name.
+Mail name [`$syshostname']:
+@end smallexample
+($syshostname is the output of `hostname --fqdn').
+
+@node  Virtual dependencies, , Mail processing packages, Appendix
+@comment  node-name,  next,  previous,  up
+@unnumberedsec Virtual dependencies
+
+Virtual packages are in the same namespace as real packages, and may
+have the same name.  The meaning of a virtual package in a
+dependency/conflicts list is exactly that of listing all the real
+packages which state that they are an instantiation of that virtual
+package.
+
+This is done with a new Provides field in the control file, with a
+syntax much like the Conflicts field.
+
+The idea is that we can have something like:
+@smallexample
+Package: elm
+Depends: mta
+
+Package: smail
+Provides: mta
+Conflicts: mta
+
+Package: sendmail
+Provides: mta
+Conflicts: mta
+@end smallexample
+@noindent The result is equivalent to elm having said
+@smallexample
+Package: elm
+Depends: smail | sendmail
+@end smallexample
+
+(There'll be a special case to say that a package may conflict with a
+virtual package which it provides - clearly ...)
+
+If there are both a real and a virtual package of the same name then
+the dependency may be satisfied (or the conflict caused) by either the
+real package or any of the virtual packages which provide it.  This is
+so that, for example, supposing we have
+@smallexample
+Package: lout
+Optional: ghostview
+@end smallexample
+(this is a fictional example - the Lout package should not mention
+ghostview), and someone else comes up with a nice PostScript
+previewer, then they can just say
+@smallexample
+Package: marvelpostview
+Provides: ghostview
+@end smallexample
+and all will work in the interim (until, say, the Lout maintainer
+changes things).
+
+If a dependency or a conflict has a version number attached then only
+real packages will be considered to see whether the relationship is
+satisfied (or prohibited, for a conflict) - it is assumed that a real
+package which provides virtual package is not of the `right' version.
+If there is demand it can be arranged that a package which provides a
+virtual package may mention a version number, though this is unlikely to
+be helpful:
+@smallexample
+Provides: mta (2.0)
+@end smallexample
+
+If you want to specify which of a set of real packages should be the
+default to satisfy a particular dependency on a virtual package, you can
+simply list the real package as alternative before the virtual one:
+@smallexample
+Package: xbaseR6
+Recommended: xsvga | x-server
+Provides: x-base, xr6shlib
+
+Package: xsvga
+Recommended: x-base
+Provides: x-server
+
+Package: x8514
+Recommended: x-base
+Provides: x-server
+@end smallexample
+
+Virtual package names should generally not be used in the names of
+@file{/etc/init.d} scripts, configuration files, logfiles, and so on, so
+that several programs providing the same virtual package name can be
+installed.
+
+@bye
diff --git a/doc/guidelines.texi.beforeeric b/doc/guidelines.texi.beforeeric
new file mode 100644 (file)
index 0000000..fb2f295
--- /dev/null
@@ -0,0 +1,1056 @@
+\input texinfo @c -*-texinfo-*-
+@setfilename guidelines.info
+
+@set DATE 26th January 1996
+
+@setchapternewpage off
+
+@iftex
+@center @titlefont{Debian GNU/Linux Packaging Guidelines}
+@tex
+\vskip2pt \hrule height 2pt width \hsize \vskip2pt
+@end tex
+@sp 0.5
+@center @value{DATE}
+@end iftex
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* debian-guidelines: (debian-guidelines).       How to make Debian packages.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@node Top, Additional Information, (dir), (dir)
+
+@ifinfo
+@top Debian GNU/Linux Packaging Guidelines
+@end ifinfo
+
+   This file documents the steps that must be taken in the preparation
+of a Debian GNU/Linux package.  All submissions to be included in the
+distribution proper and all packages to be considered for @file{contrib}
+or @file{non-free} availability @emph{must} conform to the guidelines
+and standards described in this document or they cannot be included or
+made available at the archive with the distribution.
+
+   Please read the Guidelines carefully.  If you have comments or
+questions, please contact @code{debian-devel@@pixar.com}.  If you are
+planning on going further than just contributing a package (i.e., if
+you plan to maintain it for an extended period of time or if you are
+generally interested in becoming more involved in the Project), you
+should join the @code{debian-devel} mailing list.  For more details,
+read @file{info/mailing-lists.txt}, available at any Debian GNU/Linux
+archive.
+
+   (This file was last updated on @value{DATE}.  Please check the most
+recent @file{dpkg} package at any Debian GNU/Linux archive for a
+potentially more up to date copy.)
+
+@menu
+* Additional Information::
+* Package Copyright::           A few words about the importance of
+                                understanding the package copyright.
+* Package Content::             Requirements for the package content.
+* Source Package::              Creating the source package.
+* Binary Package::              Creating the binary package.
+* Control Files::               The binary package control files.
+@end menu
+
+
+
+@node Additional Information, Package Copyright, Top, Top
+@unnumbered Additional Information
+
+   These Guidelines are intended to be fairly general.  More specific
+information is available about certain aspects of building packages,
+such as how to use the features of Init under Debian GNU/Linux.  This
+information can be found in the directory @file{project/standards}
+at any Debian GNU/Linux archive.   At the time of this writing, the
+following documents are available:
+
+@table @file
+@item README.etc-skel
+A description of @file{/etc/skel} and @file{/usr/doc/examples}.
+@item descriptions.txt
+How to write an extended (and more useful) @file{DESCRIPTION} field.
+@item README.init
+How to use the features of Init under Debian GNU/Linux in packages.
+@item mailers.txt
+How to properly configure packages to use the Debian GNU/Linux mail
+system.
+@item maintainer-script-args.txt
+All the ways that the package maintainer scripts inside a package can
+be called by dpkg.
+@item dpkg-upgrades+errors.txt
+What order things happen in during a package upgrade.
+@item virtual-dependencies.txt
+How to use ``virtual dependencies'' in packages.
+@item virtual-package-names-list.text
+The list of virtual package names currently in use, together with the
+procedure for getting new virtual package names allocated.
+@item dependency-ordering.txt
+How to properly order package names in the @file{DEPENDS} field.
+@end table
+
+   There are a number of documents that describe more technical
+details of dpkg's operation, that will probably only be of minority
+interest.  Please read them if you're doing anything complicated.
+
+@table @file
+@item auto-deconfiguration.txt
+How dpkg can sometimes automatically deconfigure packages in order to
+do bulk installations smoothly.
+@item dpkg-essential-flag.txt
+How to tell dpkg a package is essential and should not be removed.
+(This is for the use of base system packages only.)
+@item dpkg-disappear-replace.txt
+What happens when a package appears to have been completely replaced.
+@end table
+
+   In the future, we hope also to make available:
+
+@table @file
+@item copyright.txt
+How to choose a good copyright notice to attach to new programs.
+@item version-ordering.txt
+The algorithm with which packages' version numbers are compared.
+@end table
+
+   Also, you should download the sample files and the sample package
+(GNU Hello) available in @file{standards/samples}.  You may use any
+of this material as a starting point for new packages.  The following
+sample files, incidentally, are available:
+
+@itemize @bullet
+@item debian.README
+@item debian.control
+@item debian.postinst
+@item debian.postrm
+@item debian.rules
+@end itemize
+
+
+
+@node Package Copyright, Package Content, Additional Information, Top
+@unnumbered Package Copyright
+
+   Please study the copyright of your submission @emph{carefully}
+and @emph{understand it} before proceeding!  If you have doubts or
+questions, please ask!
+
+   In order to understand how we classify and distribute certain
+packages, it is important to understand the distinction between being
+freely available and being freely redistributable.
+
+   Being @dfn{freely available}, quite simply, means that the software
+can be made available freely, at least for non-commercial purposes and
+in its original, unmodified form.  This includes packages made available
+freely that have restrictions on non-commercial use, redistribution of
+modifications, etc.  Being freely available, therefore, has nothing to
+do with being able to modify and redistribute the software.  It only
+means that you can get a copy of the software without having to pay
+(and it does not necessarily mean that you can @emph{use} the software
+without having to pay---shareware is an example of freely available
+software).
+
+   @dfn{freely redistributable}, while generally being freely available,
+goes beyond just being freely available.  Freely redistributable means
+that that the software, in addition to being able to be made available
+freely, must be able to be freely modified and redistributed without
+restriction.
+
+   All submissions to be included in the distribution proper @emph{must}
+be freely redistributable.
+
+   In addition to the distribution, the Project maintains two separate
+archives of software packages with the distribution: the @file{contrib}
+archive and the @file{non-free} archive.
+
+   @file{contrib} is an archive of user-contributed packages that are
+not maintained by the Project, packages that were once maintained by the
+Project but that are no longer actively maintained, and packages that
+are maintained by the Project but that are not yet considered ready for
+inclusion in the distribution proper (i.e., ALPHA and BETA packages).
+As above, all submissions for inclusion in the @file{contrib} archive
+@emph{must} be freely redistributable.
+
+   @file{non-free} is an archive of packages with either restrictive or
+unclear terms of copying or modification.  If a package has @emph{any}
+restrictions on modification or redistribution, it can not be included
+in the distribution or @file{contrib} archive.  It can only be included
+in the @file{non-free} archive, and then only if it is freely available.
+
+   In summary, in order to be included in the distribution proper or the
+@file{contrib} archive, a package must be @emph{freely redistributable}.
+Anyone must be able to make copies of it, modify it, redistribute it with
+their modifications in place, include it on a CD-ROM, or generally sell
+it.  To be included in the @file{non-free} archive, a package may have
+restrictions, as long as the package remains @emph{freely available}.  We
+must be available to make it available freely at the archive, and anyone
+must be able to make copies of it and use it for at least non-commercial,
+personal purposes.  Software that will typically be included in
+@file{non-free} are software that does not allow commercial distribution,
+software that does not allow modification or redistribution of
+modifications, commercial ``demos'', and ``shareware''.
+
+   When in doubt, send mail to @file{iwj10@@cus.cam.ac.uk} and
+@file{imurdock@@debian.org}.  Be prepared to provide us with the
+copyright statement.  Software covered by the GPL, public domain
+software and BSD-like copyrights are safe; be wary of the phrases
+``commercial use prohibited'' and ``distribution restricted''.
+
+   Every package submission @emph{must} be accompanied by verbatim copy
+of its copyright (with the exceptions of public domain packages and
+those covered by the UCB BSD licence or the GNU GPL or LGPL; in these
+cases simply indicate which is appropriate).  This information must be
+included in a file installed to the directory @file{/usr/doc/copyright}.
+See below for details.
+
+
+
+@node Package Content, Source Package, Package Copyright, Top
+@unnumbered Package Content
+
+   The following requirements apply equally to both the binary and
+source packages.  In either case, when files have been installed,
+they must conform to the requirements described in this section.
+
+   The primary rule in Debian GNU/Linux is to follow the Linux @dfn{File
+System Standard} (@dfn{FSSTND}).  The location of installed files
+@emph{must} comply @emph{fully} with the FSSTND.  The latest version of
+this document can be found alongside the Guidelines or at
+@file{tsx-11.mit.edu} in @file{/pub/linux/docs/linux-standards/fsstnd}.
+Specific questions about following the standard should be addressed to
+Daniel Quinlan, the FSSTND coordinator, at @code{quinlan@@yggdrasil.com}.
+
+   In addition to the FSSTND, all Debian GNU/Linux packages must follow
+the guidelines below.
+
+@itemize @bullet
+@item
+Directories should be mode 755 or (for group-writability) mode 2775,
+with the exception of special ``system'' directories that need to be
+another mode.  The ownership of the directory should be consistent with
+its mode---if a directory is mode 2775, it should be owned by the group
+that needs write access to it, of course.  Use common sense in assigning
+permissions and ownerships to directories, and make sure that what is
+done is secure if it is ``non-standard''.
+
+@item
+Normal binaries should be mode 755 and owned by @code{root.root}.  If
+there is a good reason to use a different mode or ownership, you may do
+so, but you must try to be as consistent as possible with the rest of
+the system.  If you need to use a different mode or ownership, please
+discuss it with @code{imurdock@@debian.org}.
+
+@item
+Setuid binaries should normally be mode 4755 (not 4711!) and, of course,
+owned by the appropriate user.
+
+@item
+Setgid binaries should normally be mode 2755 (not 2711!) and, of course,
+owned by the appropriate group.
+
+@item
+Library files should generally be mode 644 and owned by
+@code{root.root}.  If the package requires different permissions
+or ownerships to function correctly, they should be used instead.
+
+@item
+Manual pages should be mode 644 and owned by @code{root.root}.  The
+@file{nroff} source must be installed.  You should @emph{not} install
+a preformatted ``cat page'', and you should only use sections 1 to
+9---see the FSSTND for more details.
+
+@item
+Info documents should be mode 644, owned by @code{root.root}, and
+compressed with @file{gzip -9} when installed.  The package must call
+@file{install-info} to update the Info @file{dir} file.  This should
+be done in the post-installation script (@file{postinst}), like this:
+
+@smallexample
+        install-info --quiet /usr/info/foobar.info
+@end smallexample
+
+The entries should be removed by the pre-removal script (@file{prerm}),
+like this:
+
+@example
+        install-info --quiet --remove /usr/info/foobar.info
+@end example
+
+It is also a good idea to specify a section for the Info @file{dir}
+entry.  This is done with the @file{--section} switch.  To determine
+which section to use, you should use look at @file{/usr/info/dir} on
+your system and choose the most relevant (or create a new section if
+none of the current sections are relevant).
+
+If @file{install-info} cannot find a description entry in the Info file
+you will have to supply one.  See @file{install-info}(8) for details.
+
+@item
+If a package contains any shared libraries you will have to invoke
+@file{ldconfig} in both the @file{postinst} and @file{prerm} scripts
+to correctly update the library links.  See @file{ldconfig}(8) for
+details.
+
+@item
+Any additional documentation that comes with the package can be
+installed at the discretion of the package maintainer.  Text
+documentation should be mode 644, owned by @code{root.root}, installed
+to @file{/usr/doc}, and compressed with @file{gzip -9} unless it is small.
+
+If a subdirectory of @file{/usr/doc} is warranted, please do create one.
+Please do not install DVI, PostScript, or large textual documentation to
+@file{/usr/doc}.  However, please do upload such documentation as a
+separate package so that it can be made available with the distribution.
+If a user has the need for the documentation, they can easily get it
+from the archive, CD-ROM, etc., but it should not take up disk space
+on the machines of the user who do not need or want it installed.
+
+@item
+Create a file named @file{/usr/doc/copyright/<@i{package}>} which gives
+details of the authorship and copyright of the package.  If the package
+is distributed under the GNU General Public Licence, the GNU Library
+General Public Licence or the Regents of the University of California at
+Berkeley (BSD) licence, please say so instead of including a copy of the
+licence.  The files @file{BSD}, @file{GPL}, and @file{LGPL} will be
+available in the @file{/usr/doc/copyright} directory for you to refer
+to.  @file{/usr/doc/copyright/<@i{package}>} should not be compressed.
+
+@emph{All} authorship and copyright information from the original source
+package must be included in the @file{/usr/doc/copyright/<@i{package}>}
+file.
+
+@item
+Any example files (for example, sample configuration files) should
+be placed in the directory @file{/usr/doc/examples}.  If the file is
+normally a hidden file, such as @file{.emacs}, then please call it
+@file{dot.emacs}, to avoid confusion.  Again, you may create a
+subdirectory if it is needed.
+
+@item
+All symbolic links should be relative, not absolute.  Absolute links,
+in general, cause problems when a file system is not mounted where it
+``normally'' resides (for example, when mounted via NFS).  In certain
+cases, however, relative links may also cause similar problems.  I
+have generally made links into @file{/etc} and @file{/var} absolute
+and all other links relative.  There may be other cases in which
+absolute links are necessary.
+
+Therefore, in the Makefile, do not do (even though it is easier):
+@smallexample
+        install: all
+                [...]
+                ln -fs /usr/bin/gcc /usr/bin/cc
+                [...]
+@end smallexample
+Instead, do:
+@smallexample
+                ln -fs gcc /usr/bin/cc
+@end smallexample
+        or
+@smallexample
+                ( cd /usr/bin ; ln -fs gcc cc )
+@end smallexample
+
+Please do not create hard links in the manual page directories.  In
+these cases, you should use relative symbolic links or files that
+@file{.so} (roff for `source') others instead.
+
+@item
+All command scripts should have a @code{#!} line naming the shell to be
+used to interpret them.
+
+@item
+In the case of Perl scripts this should be @code{#!/usr/bin/perl} or
+sometimes @code{#!/bin/perl}, as follows: if the script is a critical
+one that may be called when the @file{/usr} partition is unmounted or
+broken it should use @file{/bin/perl}.  Otherwise (especially if the
+script is not specifically targetted at Debian) it should use Perl's
+standard location, @file{/usr/bin/perl}.
+
+@item
+Generally the following compilation parameters should be used:
+
+@display
+   CC = gcc
+   CFLAGS = -O2 -g -Wall # sane warning options vary between programs
+   LDFLAGS = # none (or -N, if appropriate; see below)
+   install -s (or strip)
+@end display
+
+Note that all installed binaries should be stripped, either by using the
+@code{-s} flag to @file{install}, or by calling @file{strip} on the
+binaries after they have been copied into the @file{debian-tmp} but
+before the tree is made into a package.
+
+Make sure that you do not link with @code{-g}, as this makes a.out
+compilers produce huge statically linked binaries.  The @code{-g} flag
+is useful on compilation so that you have available a full set of
+debugging symbols in your built source tree, in case anyone should file
+a bug report involving (for example) a core dump.
+
+@code{-N} should only be used on binaries that are very small (less than
+8K with the @code{-N} option, roughly) and are not likely to have
+multiple instances in memory.  Do not use @code{-N} on daemons, no
+matter how small they are.
+
+It is up to the package maintainer to decide what compilation options
+are best for the package.  Certain binaries (such as
+computationally-intensive programs) may function better with certain
+flags (@code{-O3}, for example); feel free to use them.  Please use good
+judgment here.  Don't add flags for the sake of adding flags; only add
+flags if there is good reason to do so.
+
+@item
+Please check with the base system maintainer (Ian Murdock) before using
+users or groups other than @code{root} and others specified in this
+document.
+@end itemize
+
+
+
+@node Source Package, Binary Package, Package Content, Top
+@unnumbered Source Package
+
+   The source package should contain a file called @file{debian.rules}
+which contains at least the following targets, to be invoked in the top
+level directory:
+
+@smallexample
+build
+binary
+clean
+@end smallexample
+
+@file{debian.rules} should start with
+
+@example
+   #!/usr/bin/make -f
+@end example
+
+@noindent and be executable.  It is a good idea to arrange for it not
+to fail obscurely when invoked in the wrong directory, for example by
+testing for the existence of a file in the source directory.
+
+@itemize @bullet
+@item
+The @file{build} target should perform all non-interactive configuration
+and compilation of the package.  If a package has an interactive
+pre-build configuration routine, the source package should be built
+@emph{after} this has taken place.
+
+   For some packages, notably ones where the same source tree is
+compiled in different ways to produce two binary packages, the
+@file{build} target does not make much sense.  For these packages it is
+good enough to provide two (or more) targets (@file{build-a} and
+@file{build-b} or whatever) for each of the ways of building the
+package, and a @file{build} target that does nothing.  The @file{binary}
+target will have to build the package in each of the possible ways and
+make the binary package out of each.
+
+@item
+The @file{binary} target of @file{debian.rules} should be all that is
+necessary for the user to build the binary package.  The binary package
+should be created using @file{dpkg} and placed in the parent of the top
+level directory.  The next section describes how to construct binary
+packages from the @file{binary} target.
+
+@item
+The @file{clean} target should undo the effects of the @file{build}
+target and the @file{binary} target, except that it should leave alone
+any @file{../<@i{package}>-<@i{version}>.deb} file created by a run of
+@file{binary}.
+
+@item
+Additional targets may exist in @file{debian.rules}.  We recommend using
+@file{source} and @file{diff} targets to build the Debianised source
+package and the Debianisation context diff, respectively.  These files
+should be placed in @file{../foo-<@i{version}>.tar.gz} and
+@file{../foo-<@i{version}>.diff.gz}.  The @file{install} target, for
+installing into a running system direct from the Debianised source
+tree, is no longer required.  The sample @file{debian.rules} provides
+@file{source} and @file{diff} targets that should work with little or
+no alteration, providing that the package-specific variables at the top
+of the script have been properly defined.
+
+@item
+If you need to edit a @file{Makefile} where @file{configure} scripts
+are used, you should edit the @file{.in} files rather than editing
+the @file{Makefile} directly.  This allows the user to reconfigure
+the package if necessary.  You should @emph{not} configure the package
+and edit the generated @file{Makefile}!  This makes it impossible for
+someone else to later reconfigure the package.
+
+@item
+Please document your changes to the source package so that future
+package maintainers know what has been changed.  To do this, include
+a description of your changes in the @file{debian.README} (which, as
+described above, should already contain authorship and copyright
+information!) and include relevant information such as your name,
+electronic mail address, date, etc.
+
+@item
+If changes to the source code are made, please use a @file{define}.  If
+they are changes required to compile or function under Linux in general,
+use @file{LINUX}.  If it is a cosmetic or functional change, use
+@file{DEBIAN}.
+
+@item
+Create the source package using @file{tar}, and use @file{gzip -9} to
+compress it.  Source packages should be named in the form
+<@i{package}>-<@i{version}>.tar.gz---for example,
+@file{fileutils-3.9-3.tar.gz}.
+
+NB, here @code{<@i{version}>} is the full Debian version number, in the
+form @code{<@i{original_version}>-<@i{debian_revision}>} (see below),
+but the tarfile should unpack into a directory named
+@code{<@i{package}>-<@i{original_version}>} (again, see the section
+below on version numbering).
+
+@item
+Create the context diff against the original package using @file{diff
+-cNr}, and use @file{gzip -9} to compress it.  Context diffs should be
+named in the form <@i{package}>-<@i{version}>.diff.gz---for example,
+@file{fileutils-3.9-3.diff.gz}.
+@end itemize
+
+   Please note that the package and patch filenames do @emph{not} need
+to fit in MS-DOS 8+3.  They will be made available under an alternative
+8+3 name in the archive by the archive maintainer, using a symlink.
+
+
+
+@node Binary Package, Control Files, Source Package, Top
+@unnumbered Binary Package
+
+   The @file{binary} target of the source package @file{debian.rules}
+file should do the following (see the sample @file{debian.rules}
+for an implementation that you are free to modify and use in your own
+packages, of course):
+
+@itemize @bullet
+@item
+Create an empty directory in the top-level directory of the source
+package (deleting it first, if necessary), and install the files
+belonging to this package in that directory.  For example, the directory
+could be called @file{debian-tmp} and would probably contain directories
+@file{debian-tmp/usr/bin}, @file{debian-tmp/usr/lib}, etc.
+(@file{debian-tmp} is the name traditionally used, and it is used in
+the sample @file{debian.rules} file, so we will use that name in the
+Guidelines.)
+
+@item
+Make sure that all the files under @file{debian-tmp} have the correct
+ownerships and permissions (@pxref{Package Content}, for more information
+about file locations, ownerships, and permissions.)
+
+@item
+Create a subdirectory of @file{debian-tmp} called @file{DEBIAN}.  This
+directory contains the package control information, including at the
+very least the master information file named @file{control}.  The next
+section describes the semantics and syntax of the files required and
+allowed here.
+
+@item
+Run @file{dpkg} to create the binary package, using something like
+
+@smallexample
+    dpkg --build debian-tmp
+@end smallexample
+
+This will create a file called @file{debian-tmp.deb}, from the
+@file{debian-tmp} directory.  You should rename this file to
+@file{../<@i{package}>-<@i{version}>.deb} after it is built.
+
+After the @file{binary} target has done all this, the
+@file{<@i{package}>-<@i{version}>.deb} file in the parent directory is
+the binary distribution.  This file may be distributed and installed on
+any Debian GNU/Linux system with @file{dpkg} in the same manner and
+using the same methods as all packages are installed to the system.
+
+@item
+If a single source package corresponds to several binary packages, there
+should usually be a @file{debian.rules} file with a single @file{binary}
+target that builds all the binary packages involved and move all packages
+to the parent directory of that containing the source package.
+
+In this case, you should choose binary package names which are meant to
+make clear the close relationship between the binary packages and which
+source package the binary packages came from (for example, the
+@file{texinfo} source package build two binary packages: @file{texidoc}
+and @file{texinfo}).  You should place the appropriate binary package
+name in the @file{Package} field of the control file (not the source
+package name), and you should consider whether the other binary packages
+that come from the same source tree should be mentioned in the
+@file{Depends}, @file{Recommends} or @file{Suggests} fields.  You
+should put the source package name in the @file{Source} field.
+
+You should retain the source package version numbering in the
+@file{Version} field---the version number should be the same for the
+Debianised source tree and all the binary packages generated from it.
+See below for details of version numbers.
+@end itemize
+
+
+
+@node Control Files,  , Binary Package, Top
+@unnumbered Control Files
+
+   Each binary package contains, in addition to the files that comprise
+the actual package, a set of text files that control how @file{dpkg}
+installs, configures, upgrades, removes, etc. the package.  These files
+are called @dfn{control files}.  When creating the package, the control
+files should placed in a directory called @file{DEBIAN}, as described
+earlier (@pxref{Binary Package}, for further information).
+
+The control information files are:
+
+@table @code
+@item control
+The master package control information file.
+@item conffiles
+A list of package configuration files.
+@item preinst
+The package pre-installation script.
+@item postinst
+The package post-installation script.
+@item prerm
+The package pre-removal script.
+@item postrm
+The package post-removal script.
+@end table
+
+   Of these, only @file{control} is required.  The various installation
+scripts, and the configuration files list, will only be used if they are
+present.
+
+@menu
+* control::
+* conffiles::
+* Installation and Removal Scripts::
+* Dependencies and Conflicts::
+* Package Classification Fields::
+@end menu
+
+@node control, conffiles, Control Files, Control Files
+@unnumberedsec control
+
+   The @file{control} file contains a number of fields.  Each field
+begins with a field name, such as @file{Package} or @file{Version}
+(case insensitive), followed by a colon and optionally some spaces or
+tabs (a single space is conventional).  Then comes the body of the
+field, which may be several lines long; each continuation line must
+start with at least one space or tab.  (These are the same rules as
+apply to RFC822 mail headers.)  Blank lines are not permitted in the
+control file.
+
+   The required fields in the control file are the following:
+
+@table @code
+@item Package
+The name of the package.
+@item Description
+The description of the package.
+@item Maintainer
+The name and e-mail address of the maintainer of the package.
+@item Version
+The version number in the format
+@code{<@i{original_version}>-<@i{debian_revision}>}.
+@end table
+
+   Each field has a particular format and meaning for the package
+installation tools.
+
+The value of @file{Package} should be the name of the package.
+Package names must start with an alphanumeric, must be at least two
+characters, and may contain only alphanumerics and the characters
+- + . @@ : = % _ (that is, hyphen, plus, stop, at, colon, equals,
+percent and underscore).  They are not case sensitive.
+
+   The @code{Maintainer} field should be in the form
+
+@smallexample
+Joe J. Bloggs <jbloggs@@foo.com>
+@end smallexample
+
+@noindent Note that this will not be useable as an email address if
+the name given contains full stop characters, because of a silly
+restriction in the Internet mail standards.  If you want to use this
+as an email address in a program you should check for full stops and
+change the string to the form @code{jbloggs@@foo.com (Joe J. Bloggs)}
+if you find any.
+
+   The @code{Version} field should be the version number of the
+package.  For most packages which are not written specifically for
+Debian, this should be in the form
+
+@smallexample
+Version: <@i{original_version}>-<@i{debian_revision}>
+@end smallexample
+
+@noindent where @file{<@i{original_version}>} is the original package
+version number in whatever form the original package uses and
+@file{<@i{debian_revision}>} indicates which ``debianisation'' this is
+(this should usually be a plain number or perhaps a two numbers
+separated by a full stop, and should be incremented each time the
+package is changed or updated).
+
+    Packages which are written specifically for Debian do not have a
+@i{debian_revision}, and their version number should simply be
+@i{version} (which should not contain any hyphens, to avoid
+confusion).
+
+    There is an ordering imposed on version numbers, described in
+@file{version-ordering.txt}.  This ordering is designed to `do the right
+thing' in most circumstances; if your package has an version number in
+an unusual format you may need to reformat it somewhat to get the
+ordering right.  This is important because @file{dpkg} is (for example)
+reluctant to downgrade packages.
+
+   The optional fields in the control file are the following:
+
+@table @code
+@item Depends
+The names of prerequisite packages.
+@item Recommends
+The names of related, recommended packages.
+@item Suggests
+The names of related, optional packages.
+@item Conflicts
+The names of packages which conflict with this package.
+@item Provides
+The names of virtual packages which this package provides.
+@item Priority
+The `priority' of the package, as shown and used by @file{dselect}.
+@item Section
+The `section' of the package, as shown and used by @file{dselect}, and
+used as a location for the package in the distribution.
+@item Essential
+A boolean field used by the base packages.
+@end table
+
+@noindent See below for details of the semantics and syntax of these
+fields.  Most packages will need at least a @code{Depends} field.
+
+   An example of a @file{control} file would be:
+
+@example
+  Package: smail
+  Version: 3.1.29.1-13
+  Maintainer: Ian Jackson <iwj10@@cus.cam.ac.uk>
+  Recommends: pine | mailx | elm | emacs | mail-user-agent
+  Suggests: metamail
+  Depends: cron, libc5
+  Conflicts: sendmail
+  Provides: mail-transport-agent
+  Description: Electronic mail transport system.
+   Smail is the recommended mail transport agent (MTA) for Debian.
+   .
+   An MTA is the innards of the mail system - it takes messages from
+   user-friendly mailer programs and arranges for them to be delivered
+   locally or passed on to other systems as required.
+   .
+   In order to make use of it you must have one or more user level
+   mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+   and VM as mailreaders) installed.  If you wish to send messages other
+   than just to other users of your system you must also have appropriate
+   networking support, in the form of IP or UUCP.
+@end example
+
+   In this case, @file{mail-user-agent} is a virtual package
+representing any user mailer program; the actual package names
+@file{pine} is quoted for the reasons described in
+@file{dependency-ordering.txt}, and the others because older versions
+of those packages do not have the appropriate @file{Provides} field.
+
+@node conffiles, Installation and Removal Scripts, control, Control Files
+@unnumberedsec conffiles
+
+   The contents of @file{conffiles} is simply a list of configuration
+files in the package.  When installing the package, @file{dpkg} uses
+an intelligent method to update these files.  This will ensure that
+package-specific configuration files are not overwritten when a package
+is upgraded, unless the user wishes the installation tools to do so.
+
+   Typically, files listed in conffiles are package-specific
+configuration files, which (according to the Linux Filesystem Standard)
+are stored in @file{/etc}.  For example, the @code{sendmail} package may
+contain the file @file{/etc/sendmail.cf}, which we do not wish to
+overwrite automatically when the user upgrades the sendmail package.
+Only those files listed in @file{DEBIAN/conffiles} will be updated
+intelligently when a package is upgraded; all other files in the package
+will be overwritten by the upgrade process.
+
+   Configuration files which will be functional as shipped and will
+probably need little or no local editing should simply be listed the
+@file{conffiles} file; in this case you need read no further.
+
+   For packages whose configuration files will need modification on
+most systems there are two sensible approaches.  Which one is chosen
+depends on how hard the configuration problem is and how much time the
+package maintainer has available.
+
+   One option is for you to ship a minimal `best-effort' file in
+@file{/etc}, and list the file in @file{conffiles}.  This will mean that
+the user will have to go and edit the file themselves to get the package
+to work properly, of course.  The next time they upgrade the package, if
+you haven't changed the file version, their old file will be left in
+place.  If you have modified your version then the user will get a
+prompt asking them which version of the file they want, theirs or yours.
+They will then usually have to resolve the discrepancies manually.
+
+   The other option is to be preferred, if you can do it: don't put a
+copy of the configuration file in the package at all.  Instead, you
+check in the postinst whether the file exists, and if it doesn't you
+prompt the user for the information you need to create a good one.  This
+is obviously harder work.
+
+  You also have to remember that you will have to keep up with your
+package's changes: if you discover a bug in the program which generates
+the configuration file, or if the format of the file changes from one
+version to the next, you will have to arrange for the postinst script to
+do something sensible---usually this will mean editing the installed
+configuration file to remove the problem or change the syntax.  You will
+have to do this very carefully, since the user may have changed the
+file, perhaps to fix the very problem that your script is trying to deal
+with---you will have to detect these situations and deal with them
+correctly.
+
+  If you do go down this route it's probably a good idea to make the
+program that generates the configuration file(s) a separate program in
+@file{/usr/sbin}, by convention called @i{package}@code{config}, and
+then run that if appropriate from the post-installation script.  The
+@i{package}@code{config} program should not unquestioningly overwrite an
+existing configuration---if its mode of operation is geared towards
+setting up a package for the first time (rather than any arbitrary
+reconfiguration later) you should have it check whether the
+configuration already exists, and require a @code{--force} flag to
+overwrite it.
+
+   @file{conffiles} should almost certainly list all the files contained
+in your package in the @file{/etc} directory.  There may also be other
+files somewhere that the user is expected to edit, which should also be
+included.  Note, however, that the FSSTND specifies that configuration
+files must be in @file{/etc}.  No Debian package should contain
+configuration files in @file{/usr/etc}, and all programs should refer to
+configuration files in @file{/etc}.
+
+@noindent For example, the TCP/IP package might use a conffiles which contains
+
+@example
+  /etc/init.d/netbase
+  /etc/gateways
+  /etc/protocols
+  /etc/services
+  /etc/hosts.allow
+  /etc/hosts.deny
+  /etc/rpc
+@end example
+
+@noindent and so on; the files
+
+@example
+  /etc/hosts
+  /etc/inetd.conf
+  /etc/host.conf
+  /etc/networks
+  /etc/resolv.conf
+@end example
+
+@noindent might be generated by an interactive configuration program,
+and would then not be included in the package or listed in the
+@file{conffiles}.
+
+@node Installation and Removal Scripts, Dependencies and Conflicts, conffiles, Control Files
+@unnumberedsec Installation and Removal Scripts
+
+   The scripts @file{preinst}, @file{postinst}, @file{prerm}, and
+@file{postrm} are optional (Bash or Perl) scripts.  As the names
+would indicate, if these scripts exist, they will be executed before
+installing the package, after installation, before package removal,
+and after removal, respectively.
+
+   They are given arguments which indicate the precise situation and
+action being performed---see @file{maintainer-script-args.txt} for
+details of exactly when each of the scripts is invoked and what its
+arguments are.  Extra arguments and situations may be added later, so
+you should not test the number of arguments to your script to determine
+the situation, and you should choose the sense of your `if it is this
+then do this otherwise do that' tests carefully.
+
+   These scripts can be used to perform any site-specific package
+configuration.
+
+   Because the scripts will be exectued by the dpkg front-end, it is
+guaranteed that the scripts will be executed interactively.  User input
+from the scripts should be read from standard input, not the user's
+terminal.  Similarly, output should be sent to standard output.
+
+   If your maintainer scripts need to prompt for passwords and/or do
+@i{full-screen} interaction should do these things to and from
+@file{/dev/tty}, since @file{dpkg} will at some point redirect scripts'
+standard input and output so that it can log the installation process.
+Likewise, because these scripts may be executed with standard output
+redirected into a pipe for logging purposes, Perl scripts should set
+unbuffered output by setting @code{$|=1} so that the output is printed
+immediately rather than being buffered.
+
+   The scripts must be idempotent, and they must clean up after
+themselves properly.  Ie, they must do the right thing if run multiple
+times, even if previous runs failed halfway through.  This is so that if
+any errors occur, or if the @file{dpkg} run is interrupted, the user can
+recover by rerunning @file{dpkg}, and/or by upgrading to a new version
+and then rerunning the failed operation.
+
+   These scripts should avoid producing output which it is unnecessary
+for the user to see and should rely on @file{dpkg} to stave off boredom
+on the part of a user installing many packages.  This means, amongst
+other things, using the @file{--quiet} option on @file{install-info}.
+
+   Packages should try to minimise the amount of prompting they need to
+do, and they should ensure that the user will only every be asked each
+question once.  This means that packages should try to use appropriate
+shared configuration files (such as @file{/etc/papersize} and
+@file{/etc/news/server}), rather than each prompting for their own list
+of required pieces of information.
+
+   It also means that an upgrade should not ask the same questions
+again, unless the user has used @code{dpkg --purge} to remove the
+package's configuration.  The answers to configuration questions should
+be stored in an appropriate place in @file{/etc} so that the user can
+modify them, and how this has been done should be documented.
+
+   If a package has a vitally important piece of information to pass to
+the user (such as "don't run me as I am, you must edit the following
+configuration files first or you risk your system emitting
+badly-formatted messages"), it should display this in the
+@file{postinst} script and prompt the user to hit Return to acknowledge
+the message.  Copyright messages do not count as vitally important (they
+belong in @file{/usr/doc/copyright}; neither do instructions on how to
+use a program (these should be in on line documentation, where all the
+users can see them).
+
+   They should return a zero exit status for success, or a nonzero one
+for failure.  Note that if a script is a @code{#!/bin/sh} script it
+should probably start with @code{set -e}, to avoid continuing after
+errors---see @file{bash}(1) for details.  Perl scripts should check for
+errors when making calls such as @code{open}, @code{print},
+@code{close}, @code{rename} and @code{system}.
+
+   If these scripts exist they should be left in the @file{DEBIAN}
+directory with execute permission enabled and should contain an
+appropriate @code{#!} line, such as @code{#!/bin/bash} for a
+@code{bash} script or @code{#!/bin/perl} for a Perl script (see
+above).
+
+@node Dependencies and Conflicts, Package Classification Fields, Installation and Removal Scripts, Control Files
+@unnumberedsec Conflicts, Depends, Suggests, Recommends and Provides
+
+   The @file{Depends} field lists packages that are required for this
+package to provide a significant amount of functionality.  The package
+maintenance software will not allow a package to be installed without
+also installing packages listed in its @code{Depends} field, and will
+run the @code{postinst} scripts of packages listed in @code{Depends}
+fields before those of the packages which depend on them, and run the
+@code{prerm} scripts before.
+
+   Packages containing dynamically-linked executable binaries (this
+includes almost all C programs) should include a @file{Depends} field
+which mentions the shared C library required for the program to run.
+For a.out binaries linked against @file{libc.so.4} the relevant package
+name is @file{libc}; for ELF binaries linked against @file{libc.so.5}
+the relevant package name is @file{libc5}.
+
+   The @code{Recommends} field lists packages that would be found
+together with this one in all but unusual installations.  The user-level
+package maintenance program @file{dselect} will warn the user if they
+select a package without those listed in its @code{Recommends} field.
+Note that @code{Recommends} fields don't currently have any implications
+for the order in which the maintainer scripts are run.
+
+   The @code{Suggests} field lists packages that are related to this one
+and can perhaps enhance its usefulness, but without which installing
+this package is perfectly reasonable.  The package maintenance software
+will not moan at the user for not selecting @code{Suggests} related
+packages, but may use the information in the @code{Suggests} field to
+assist the user during package selection.
+
+   The syntax of @code{Depends}, @code{Recommends} and @code{Suggests}
+is a list of groups of alternative packages.  Each group is a list of
+packages separated by vertical bar (or `pipe') symbols, @code{|}.  The
+groups are separated by commas.  Each package is a package name
+optionally followed by a version number specification in parentheses.  A
+version number may start with a @code{>=}, in which case that version or
+any later will match, or @code{<=} for that version or any earlier
+version. A version number starting with a @code{>>} or @code{<<} will
+respectively match any later or earlier version. If a version number or
+a version number starting with @code{=} is specified an exact match is
+required. Commas are to be read as `AND', and pipes as `OR', with pipes
+binding more tightly.
+
+   Versions of dpkg before 1.0.9 used @code{<} and @code{>} for
+@code{<=} and @code{>=} (these are still supported for backward
+compatibility), and did not support @code{<<} and @code{>>}.
+
+   The @code{Conflicts} field lists packages that conflict with this
+one, for example by containing files with the same names (an example
+would be Smail vs. Sendmail).  The package maintenance software will not
+allow conflicting packages to be installed.  Two conflicting packages
+should each include a @code{Conflicts} line mentioning the other.
+
+   The syntax of @code{Conflicts} is a list of package names (with
+optional version numbers), separated by commas (and optional
+whitespace).  In the @code{Conflicts} field the comma should be read as
+`OR'.
+
+   The @code{Provides} field lists the names of any `virtual packages'
+of which this packages is to be considered an instantiation.  Virtual
+packages are used to allow packages to refer to a service they require
+(such as the availability of @file{/usr/sbin/sendmail}) without having
+to know the names of all the relevant packages.  The virtual package
+names defined in @code{Provides} fields may be used in other packages'
+@code{Depends}, @code{Recommends}, @code{Suggests} and @code{Conflicts}
+fields.  For more information about how to use virtual packages and
+which virtual package names to use read @file{virtual-dependencies.txt}
+and @file{virtual-package-names-list.text}.
+
+   The syntax of @code{Provides} is a list of package names separated by
+commas (and optional whitespace).
+
+@node Package Classification Fields,  , Dependencies and Conflicts, Control Files
+@unnumberedsec Priority, Section and Essential
+
+   The @code{Priority} and @code{Section} fields are used by
+@file{dselect} when displaying the list of packages to the user.  There
+is no need to put them into a package, since these are usually set by
+the distribution maintainers in the @file{Packages} file.
+
+   However, if a user installs a package which is not part of the
+standard distribution, or without downloading and updating from a new
+@file{Packages} file, the information about the priority and section of
+a package will be absent, and the @file{dselect} package listing will
+have the package listed under `unclassified'.  It is permissible for a
+package to include @code{Section} or @code{Priority} fields to improve
+this; however, if you do this you should make sure you keep the
+information up to date so that users are not shown conflicting
+information.  The @code{Section} field can also be used by the
+distribution maintainers as a suggestion about which section you think
+is most appropriate for your package.
+
+  The @code{Essential} field should only appear in packages in the
+installation's base system.  If it is set to @code{yes} then @file{dpkg}
+will not remove the package even if asked to, and will make certain
+minor modifications to its installation procedures.  The only other
+legal value is @code{no}, which is equivalent to the absence of the
+field.
+
+@bye
+
+@c local variables:
+@c kept-new-versions: 100
+@c version-control:   t
+@c end:
diff --git a/doc/guidelines.texi.rej b/doc/guidelines.texi.rej
new file mode 100644 (file)
index 0000000..1535400
--- /dev/null
@@ -0,0 +1,33 @@
+***************
+*** 376,390 ****
+  Generally the following compilation parameters should be used:
+  
+  @display
+-         CC = gcc
+-         CFLAGS = -O2
+-         LDFLAGS = -s (and -N, if appropriate; see below)
+  @end display
+  
+  All installed binaries should be stripped, hence @code{-s}.  @code{-N}
+  should only be used on binaries that are very small (less than 8K with
+  the @code{-N} option, roughly) and are not likely to have multiple
+- instances in memory.  Do not use @code{-N} on daemons, no matter how
+  small they are.
+  
+  It is up to the package maintainer to decide what compilation options
+--- 383,397 ----
+  Generally the following compilation parameters should be used:
+  
+  @display
++ CC = gcc
++ CFLAGS = -O2
++ LDFLAGS = -s (and -N, if appropriate; see below)
+  @end display
+  
+  All installed binaries should be stripped, hence @code{-s}.  @code{-N}
+  should only be used on binaries that are very small (less than 8K with
+  the @code{-N} option, roughly) and are not likely to have multiple
++ instances in memory.  Don't use @code{-N} on daemons, no matter how
+  small they are.
+  
+  It is up to the package maintainer to decide what compilation options
diff --git a/doc/junk b/doc/junk
new file mode 100644 (file)
index 0000000..46c3587
--- /dev/null
+++ b/doc/junk
@@ -0,0 +1,29 @@
+
+@table @file
+@item virtual-package-names-list.text
+The list of virtual package names currently in use, together with the
+procedure for getting new virtual package names allocated.
+@item (obsolete) README.etc-skel
+A description of @file{/etc/skel} and @file{/usr/doc/examples}
+(@pxref{Skeleton and examples}).
+@item (obsolete) descriptions.txt
+The description of the package. How to write an extended and more useful
+description field (@pxref{Package description}).
+@item (obsolete) README.init
+How to use the features of Init under Debian GNU/Linux in packages
+(@pxref{Configuration of init}).
+@item (obsolete) mailers.txt
+How to properly configure packages to use the Debian GNU/Linux mail
+nnsystem (@pxref{Mail processing packages}).
+@item (obsolete) maintainer-script-args.txt
+All the ways that the package maintainer scripts inside a package can be
+called by dpkg (@pxref{Maintainer script arguments}).
+@item (obsolete) dpkg-upgrades+errors.txt
+What order things happen in during a package upgrade (@pxref{What
+happends during a package upgrade?}).
+@item (obsolete) virtual-dependencies.txt
+How to use ``virtual dependencies'' in packages (@pxref{Virtual
+dependencies}).
+@item (obsolete) dependency-ordering.txt
+How to properly order package names in the @file{DEPENDS} field.
+@end table
diff --git a/doc/maintainer-script-args.txt b/doc/maintainer-script-args.txt
new file mode 100644 (file)
index 0000000..a1cd3c7
--- /dev/null
@@ -0,0 +1,173 @@
+Richard Kettlewell has asked me to document this, so here is a brief
+summary.  More documentation will probably have to wait until someone
+has time ...
+
+... hmm, it has turned out not to be so brief, and I've spent the last
+hour or so writing it.  Perhaps someone can use it as the basis for a
+spec or a manpage or something.
+
+In all cases version numbers are <version>-<revision>, if the package
+has both, or just <version>.  `upgrade' is used even when the new
+version number looks lower than the old.
+
+*** SUMMARY - listing of possible scripts with arguments:
+
+ <new preinst> install
+ <new preinst> install <old-version>
+ <new preinst> upgrade <old-version>
+ <old preinst> abort-upgrade <new-version>
+
+ <postinst> configure
+ <old postinst> abort-upgrade <new version>
+ <conflictor's postinst> abort-remove in-favour <package> <new version>
+ <deconfigured's postinst> abort-deconfigure \
+               in-favour <package-being-installed-but-failed> <version>
+               removing <conflicting-package> <version>
+
+ <prerm> remove
+ <old prerm> upgrade <new version>
+ <new prerm> failed-upgrade <old-vppersion>
+ <conflictor's prerm> remove in-favour <package> <new version>
+ <deconfigured's prerm> deconfigure \
+               in-favour <package-being-installed> <version> \
+               removing <conflicting-package> <version>
+
+ <postrm> remove
+ <postrm> purge
+ <old postrm> upgrade <new-version>
+ <new postrm> failed-upgrade <old-version>
+ <new postrm> abort-install
+ <new postrm> abort-install <old-version>
+ <new postrm> abort-upgrade <old-version>
+ <disappearer's postrm> disappear <overwriter> <new version>
+
+*** INSTALLATION (unpack):
+
+The procedure on installation/upgrade/overwrite/disappear (ie, when
+running dpkg --unpack, or the unpack stage of dpkg --install) is as
+follows.  In each case if an error occurs the actions in are general
+run backwards - this means that the maintainer scripts are run with
+different arguments in reverse order.  These are the `error unwind'
+calls listed below.
+
+1a. If a version the package is already installed, call
+       <old prerm> upgrade <new version>
+1b. If this gives an error (ie, a non-zero exit status), dpkg will
+attempt instead:
+       <new prerm> failed-upgrade <old-version>
+   ... error unwind, for both the above cases:
+       <old postinst> abort-upgrade <new version>
+
+2. If a `conflicting' package is being removed at the same time:
+2a. If any packages depended on that conflicting package and
+--auto-deconfigure is specified, call, for each such package:
+       <deconfigured's prerm> deconfigure \
+               in-favour <package-being-installed> <version> \
+               removing <conflicting-package> <version>
+   ... error unwind:
+       <deconfigured's postinst> abort-deconfigure \
+               in-favour <package-being-installed-but-failed> <version>
+               removing <conflicting-package> <version>
+The deconfigured packages are marked as requiring configuration, so
+that if --install is used they will be configured again if possible.
+2b. To prepare for removal of the conflicting package, call:
+       <conflictor's prerm> remove in-favour <package> <new version>
+   ... error unwind:
+       <conflictor's postinst> abort-remove in-favour <package> <new version>
+
+3a. If the package is being upgraded, call
+       <new preinst> upgrade <old-version>
+3b. otherwise, if the package had some configuration files from a
+previous version installed (ie, it is in the conffiles-only state):
+       <new preinst> install <old-version>
+3c. otherwise (ie, the package was completely purged):
+       <new preinst> install
+   ... error unwind versions, respectively:
+       <new postrm> abort-upgrade <old-version>
+       <new postrm> abort-install <old-version>
+       <new postrm> abort-install
+
+4. The new package's files are unpacked, overwriting any that may be
+on the system already, for example any from the old package or from
+another package (backups of the old files are left around, and if
+anything goes wrong dpkg will attempt to put them back as part of the
+error unwind).
+
+5a. If the package is being upgraded, call
+       <old postrm> upgrade <new-version>
+5b. If this fails, dpkg will attempt:
+       <new postrm> failed-upgrade <old-version>
+   ... error unwind, for both cases:
+       <old preinst> abort-upgrade <new-version>
+
+This is the point of no return - if dpkg gets this far, it won't back
+off past this point if an error occurs.  This will leave the package
+in a fairly bad state, which will require a successful reinstallation
+to clear up, but it's when dpkg starts doing things that are
+irreversible.
+
+6. Any files which were in the old version of the package but not in
+   the new are removed.
+7. The new file list replaces the old.
+8. The new maintainer scripts replace the old.
+
+9. Any packages all of whose files have been overwritten during the
+installation, and which aren't required for dependencies, are
+considered to have been removed.  For each such package, 
+9a. dpkg calls:
+       <disappearer's postrm> disappear <overwriter> <new version>
+9b. The package's maintainer scripts are removed.
+9c. It is noted in the status database as being in a sane state,
+namely not installed (any conffiles it may have are ignored).
+Note that disappearing packages don't have their prerm called, because
+dpkg doesn't know in advance that the package is going to vanish.
+
+10. Any files in the package we're unpacking that are also listed in
+the file lists of other packages are removed from those lists.  (This
+will lobotomise the file list of the `conflicting' package if there is
+one.)
+
+11. The backup files made at 4. are deleted.
+12. The new package's status is now sane, and recorded as `unpacked'.
+
+Here is another point of no return - if the conflicting package's
+removal fails we don't unwind the rest of the installation; the
+conflicting package is left in a half-removed limbo.
+
+13. If there was a conflicting package we go and do the removal
+actions, starting from point 2. of the removal, below.
+
+
+*** CONFIGURATION:
+
+When we configure a package (this happens with dpkg --install, or with
+--configure), we first update the conffiles and then call:
+       <postinst> configure
+(I'm planning to make available as an argument the version of the most
+recent successfully-configured version of the package.)
+
+No attempt is made to unwind after errors during configuration.
+
+
+*** REMOVAL:
+
+1.     <prerm> remove
+
+2. The package's files are removed (except conffiles).
+
+3.     <postrm> remove
+
+4. All the maintainer scripts except the postrm are removed.
+
+If we aren't purging the package we stop here.  Note that packages
+which have no postrm and no conffiles are automatically purged when
+removed, as there is no difference except for the dpkg status.
+
+5. The conffiles and any backup files (~-files, #*# files, %-files,
+.dpkg-{old,new,tmp}, &c &c &c) are removed.
+
+6.     <postrm> purge
+
+7. The package's file list is removed.
+
+No attempt is made to unwind after errors during removal.
diff --git a/doc/upgrades+errors.txt b/doc/upgrades+errors.txt
new file mode 100644 (file)
index 0000000..09b5bd5
--- /dev/null
@@ -0,0 +1,220 @@
+From ian Wed Nov 16 15:12:56 1994 
+X-VM-v5-Data: ([nil nil nil nil t nil nil nil nil]
+       [nil "Wed" "16" "November" "1994" "15:12:56" nil "ian" "ian" "" nil "dpkg - upgrades and error handling, take 2" "^To:" nil nil "11" nil nil nil nil]
+       nil)
+To: Debian dpkg list <debian-dpkg@pixar.com>
+Subject: dpkg - upgrades and error handling, take 2
+
+Here is a revised scheme for upgrade procedure and error handling.
+
+If you can see any serious problems with this please say so; if there
+are no compelling reasons not to I intend to implement the following.
+
+
+Procedure for new unpack:
+  * Run the preinst script (argument: `install').
+  * Back up the conffiles.
+  * Unpack the files in the package.
+This leaves the package in the `unpacked but not configured'
+state.
+
+If the preinst fails the installation is aborted immediately, leaving
+the package in whatever state it was originally.  The preinst should
+clean up after its own failure.
+
+If the conffiles can't be backed up then any which have been are
+restored to their original names, if possible, and the postrm script
+is run if there is one (argument: `abort-install').  This leaves the
+package in its original state.
+
+If the unpack fails any files already unpacked are removed, the
+conffiles are restored to their original names, and the postrm is run
+(argument: `abort-install').  Again, the package remains in its
+original state.
+
+Errors found when running the postrm are ignored.
+
+
+Procedure for configuration:
+  * Do the conffile updating, including prompting, as in the spec.
+  * Run the postinst (argument: `configure').
+
+If the conffile updating fails anything that has been done is undone
+if possible and the package is left in the `unpacked but not
+configured' state.
+
+If the postinst fails dpkg gives up and leaves the package in the
+`postinst failed' state.  Next time it will just rerun the
+postinst; if the postinst has a bug a new *.deb can be provided.  In
+that case installation of the new *.deb will proceed almost as if it
+were a normal upgrade.
+
+
+Procedure for removal:
+  * Run the prerm (argument: `remove').
+  * Delete the files in the package and any resulting empty
+    directories.
+  * Run the postrm (argument: `remove').
+
+If the prerm fails dpkg leaves the package in the original state; if
+the user asks again to remove the package the prerm will be run again.
+
+If the deletion fails the removal is aborted, and the package left in
+the `removal failed' state.
+
+If the postrm fails dpkg leaves the package in the `removal failed'
+state.
+
+If the package is in the `removal failed' state to start with it will
+start again with deleting the files and empty directories and rerun
+the postrm.
+
+If the postrm has a bug a new *.deb must be installed first (using the
+upgrade procedure) and then removed.  This is so that a working postrm
+script is provided.
+
+
+Procedure for upgrade:
+   * Run the old prerm script (arguments: `upgrade <new-version>').
+   * Move aside all existing files (not directories) for the
+     package being overwritten.
+   * Run the old postrm script (arguments: `upgrade <new-version>').
+   * Run the new preinst script (arguments: `upgrade <old-version>').
+   * Back up the conffiles.
+   * Unpack the files in the package.
+   * Remove the files which were moved aside.
+This leaves the package in the `unpacked but not configured'
+state.
+
+Errors during the removal of the files which were moved aside are
+flagged, but don't cause dpkg to attempt to abort the upgrade.
+
+If the old prerm or postrm script fails the corresponding script from
+the new package is run instead (arguments: `failed-upgrade
+<old-version>').  If there is no corresponding script in the new
+package the error is ignored.
+
+If any other stage fails, or if we try to use the script in the new
+package because the old prerm/postrm script failed but the new script
+fails too, we attempt to undo everything in reverse order, as follows:
+
+Unpacking the files in the package is undone by removing the files we
+unpacked and any empty directories, in reverse order.  Errors are
+ignored.
+
+The conffiles backup is undone as much as possible, ignoring errors.
+
+The new preinst is undone by running the new postrm (arguments:
+`abort-upgrade <old-version>'); errors are ignored.
+
+The old postrm is undone by running the old preinst (arguments:
+`abort-upgrade <new-version>'); errors are ignored.
+
+Files we backed up are restored if possible; errors here leave the
+package in the `removal failed' state.
+
+The old prerm is undone by running the old postinst (arguments:
+`abort-upgrade <new-version>').  Errors here leave the package in the
+`postinst failed' state.
+
+
+Ian.
+
+From ian Wed May 17 02:14:09 +0100 1995
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+       [nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+       nil)
+To: Debian developers list <debian-devel@pixar.com>
+Subject: New dpkg overwriting handling
+
+Here is a comment that describes how I plan to have the new C dpkg act
+with respect to overwriting, upgrades, &c.
+
+The sequence of events during upgrade will change, because the removal
+of the old package and the installation of the new will take place
+together.  So we have,
+
+ (noninteractive, during `dpkg --unpack' ...)
+  old prerm
+  new preinst
+  unpack new archive, possibly overwriting old files
+  delete any files in the old but not the new package
+  old postrm
+  run `postrm disappear' for any vanished packages, then forget them
+
+ (interactive, during `dpkg --configure' ...)
+  conffile updates
+  new postinst
+
+Furthermore, conffiles will not be backed up before unpack and have
+the user's old version hang around as `.dpkg-tmp'; instead, the old
+file will be left in place and the new one extracted into `.dpkg-new'.
+It will only be installed (if desired) at a conffile update.
+
+Thanks to Bruce for providing nice tar-in-a-function code that will
+allow me to handle each file individually rather than having tar splat
+them all out (and often do it buggily anyway).
+
+Ian.
+
+  /*
+   * Now we unpack the archive, backing things up as we go.
+   * For each file, we check to see if it already exists.
+   * There are several possibilities:
+   * + We are trying to install a non-directory ...
+   *  - It doesn't exist.  In this case we simply extract it.
+   *  - It is a plain file, device, symlink, &c.  We do an `atomic
+   *    overwrite' using link() and rename(), but leave a backup copy.
+   *    Later, when we delete the backup, we remove it from any other
+   *    packages' lists.
+   * -  It is a directory.  We move it aside and extract the file.
+   *    Later, when we delete the backed-up directory, we remove it
+   *    from any other packages' lists.
+   * + We are trying to install a directory ...
+   *  - It doesn't exist.  We create it with the appropriate modes.
+   *  - It is a plain file or a symlink.  We move it aside and create
+   *    the directory.  Later, when we delete the backup, we remove it
+   *    from any other packages' lists.
+   *  - It exists as a directory.  We do nothing.
+   *
+   *                   Install non-dir              Install dir
+   *  Exists not               X                          C
+   *  File/node/symlink       LXR                        BCR
+   *  Directory               BXR                         -
+   *
+   *    C: create directory
+   *    X: extract file/node/link
+   *   LX: atomic overwrite leaving backup
+   *    B: ordinary backup
+   *    R: later remove from other packages' lists
+   *    -: do nothing
+   * 
+   * After we've done this we go through the remaining things in the
+   * lists of packages we're trying to remove (including the old
+   * version of the current package).  This happens in reverse order,
+   * so that we process files before the directories (or symlinks-to-
+   * directories) containing them.
+   * + If the thing is a conffile then we leave it alone for the purge
+   *   operation.
+   * + Otherwise, there are several possibilities too:
+   *  - The listed thing does not exist.  We ignore it.
+   *  - The listed thing is a directory or a symlink to a directory.
+   *    We delete it only if it isn't listed in any other package.
+   *  - The listed thing is not a directory or a symlink to one (ie,
+   *    it's a plain file, device, pipe, &c, or a symlink to one, or a
+   *    dangling symlink).  We delete it.
+   * The removed packages' list becomes empty (of course, the new
+   * version of the package we're installing will have a new list,
+   * which replaces the old version's list).
+   *
+   * If at any stage we remove a file from a package's list, and the
+   * package isn't one we're already processing, and the package's
+   * list becomes empty as a result, we `vanish' the package.  This
+   * means that we run its postrm with the `disappear' argument, and
+   * put the package in the `not-installed' state.  Its conffiles are
+   * ignored and forgotten about.
+   *
+   * NOTE THAT THE OLD POSTRM IS RUN AFTER THE NEW PREINST, since the
+   * files get replaced `as we go'.
+   */
+
diff --git a/doc/version-ordering.txt b/doc/version-ordering.txt
new file mode 100644 (file)
index 0000000..7bbda63
--- /dev/null
@@ -0,0 +1,59 @@
+(This has been edited to conform to the intent in dpkg 1.0.16.
+ When recent versions of dpkg compare versions they break the Version
+ into an upstream version and debian revision first, by splitting the
+ Version at the last hyphen.  The revisions are only considered if the
+ upstream versions compare equal.)
+
+To: debian-devel@pixar.com
+Subject: Re: dpkg 0.93.8 released
+
+[...]
+Well, here is what I came up with after a bit of thought and testing.
+I propose the following algorithm for comparing version numbers:
+
+   forever {
+     remove initial non-digit substring from string a
+     remove initial non-digit substring from string b
+     compare initial non-digit substrings lexically,
+       counting letters as coming before punctuation
+     if (they differ) return the answer
+     remove initial digit substring from string a
+     remove initial digit substring from string b
+     compare initial digit substrings numerically
+     if (they differ) return the answer
+     if (both strings are now empty)
+       the version numbers are the same, stop
+     if (one string is now empty)
+       it is the `lesser', return the answer
+   }
+
+This will have the desired results:
+   2.1 < 2.7 < 2.7a < 2.7a-2 < 2.15
+
+An implementation in Perl is attached below.
+
+Ian.
+
+#!/usr/bin/perl --
+
+if (@ARGV) {
+    print &compare(@ARGV),"\n";
+} else {
+    while(<>) { chop; chop($x=<>); print &compare($_,$x),"\n"; }
+}                
+
+sub compare {
+    local ($a,$b) = @_;
+    do {
+        $a =~ s/^\D*//; $ad= $&; $ad =~ s/\W/ /g;
+        $b =~ s/^\D*//; $bd= $&; $bd =~ s/\W/ /g;
+print "\t[$ad|$a] [$bd|$b]\n";
+        $cm = $ad cmp $bd;  return $cm if $cm;
+        $a =~ s/^\d*//; $ad= $&;
+        $b =~ s/^\d*//; $bd= $&;
+print "\t<$ad|$a> <$bd|$b>\n";
+        $cm = $ad <=> $bd;  return $cm if $cm;
+    } while (length($a) && length($b));
+print "\t{$a} {$b}\n";
+    return length($a) cmp length($b);
+}
diff --git a/doc/virtual-dependencies.txt b/doc/virtual-dependencies.txt
new file mode 100644 (file)
index 0000000..1f45eb7
--- /dev/null
@@ -0,0 +1,105 @@
+To: Debian users list <debian-user@pixar.com>
+Subject: dpkg 0.93.36: dselect does virtual packages
+
+This release contains virtual package support in the C parts of the
+system, which at the moment includes dselect and dpkg-deb.
+
+It works as I outlined in a mail to debian-devel a little while ago.
+
+Package maintainers: please start adding `Provides:' fields to your
+packages.  dselect will use and understand them; dpkg-deb will check
+the syntax of the Provides field instead of warning you about it.
+dpkg will not understand the new field and will ignore it.
+
+When almost all the packages have Provides: fields in place we can
+start replacing old-style Recommended: fields.
+
+Note that we can't change Depends: fields since they're also
+interpreted by dpkg, which doesn't know about Provides (yet).
+
+[...]
+--------------------
+
+From: iwj10@cus.cam.ac.uk (Ian Jackson)
+To: debian-devel@pixar.com
+Subject: `virtual' packages in Depends, Conflicts &c
+Date: Fri, 31 Mar 95 15:44 BST
+
+We're starting to have a problem with package name changes and
+multiple packages providing the same service.
+
+I liked the idea (put forward by [Bruce Perens]) of having `virtual'
+packages; it seems that it would solve many of these problems straight
+away.
+
+What I'm proposing to do is as follows:
+
+Depends, Conflicts, Recommended and Optional lines will now be able to
+contain `virtual' package names as well as real package names.
+
+Virtual packages are in the same namespace as real packages, and may
+have the same name.  The meaning of a virtual package in a
+dependency/conflicts list is exactly that of listing all the real
+packages which state that they are an instantiation of that virtual
+package.
+
+This is done with a new Provides field in the control file, with a
+syntax much like the Conflicts field.
+
+The idea is that we can have something like:
+ Package: elm
+ Depends: mta
+
+ Package: smail
+ Provides: mta
+ Conflicts: mta
+
+ Package: sendmail
+ Provides: mta
+ Conflicts: mta
+&c.  The result is equivalent to elm having said
+ Depends: smail | sendmail
+
+(There'll be a special case to say that a package may conflict with a
+virtual package which it provides - clearly ...)
+
+If there are both a real and a virtual package of the same name then
+the dependency may be satisfied (or the conflict caused) by either the
+real package or any of the virtual packages which provide it.  This is
+so that, for example, supposing we have
+ Package: lout
+ Optional: ghostview
+(this is a fictional example - the Lout package shouldn't mention
+ghostview), and someone else comes up with a nice PostScript
+previewer, then they can just say
+ Package: marvelpostview
+ Provides: ghostview
+and all will work in the interim (until, say, the Lout maintainer
+changes things).
+
+If a dependency or a conflict has a version number attached then only
+real packages will be considered to see whether the relationship is
+satisfied (or prohibited, for a conflict) - it is assumed that a real
+package which provides virtual package is not of the `right' version.
+If there is demand I could arrange that a package which provides a
+virtual package may mention a version number, eg.
+  Provides: mta (2.0)
+though I tbink this is unlikely to be helpful.
+
+If you want to specify which of a set of real packages should be the
+default to satisfy a particular dependency on a virtual package, you
+can simply list the real package as alternative before the virtual
+one.  E.g.:
+ Package: xbaseR6
+ Recommended: xsvga | x-server
+ Provides: x-base, xr6shlib
+
+ Package: xsvga
+ Recommended: x-base
+ Provides: x-server
+
+ Package: x8514
+ Recommended: x-base
+ Provides: x-server
+
+Ian.
diff --git a/dpkg-deb/Makefile.in b/dpkg-deb/Makefile.in
new file mode 100644 (file)
index 0000000..9186619
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+
+SRC = main.c build.c extract.c info.c
+OBJ = main.o build.o extract.o info.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib -ldpkg $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+
+.SUFFIXES:     .c .o
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+all:           dpkg-deb
+
+dpkg-deb:      $(OBJ) ../lib/libdpkg.a
+               $(CC) $(LDFLAGS) -o dpkg-deb $(OBJ) $(LIBS)
+
+$(OBJ):                                dpkg-deb.h ../config.h ../include/dpkg.h
+build.o:                       ../include/dpkg-db.h
+info.o extract.o main.o:       ../include/myopt.h
+main.o:                                ../version.h
+
+clean:
+               rm -f *.o core dpkg-deb
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
+               $(INSTALL_PROGRAM) -s dpkg-deb $(bindir)/dpkg-deb
+               $(INSTALL_DATA) dpkg-deb.8 $(man8dir)/dpkg-deb.$(man8)
diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
new file mode 100644 (file)
index 0000000..79e9f36
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * build.c - building archives
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-deb.h"
+
+#ifndef S_ISLNK
+# define S_ISLNK(mode) ((mode&0xF000) == S_IFLNK)
+#endif
+
+static void checkversion(const char *vstring, const char *fieldname, int *errs) {
+  const char *p;
+  if (!vstring || !*vstring) return;
+  for (p=vstring; *p; p++) if (isdigit(*p)) return;
+  fprintf(stderr, BACKEND " - error: %s field (`%s') doesn't contain any digits\n",
+          fieldname, vstring);
+  (*errs)++;
+}
+
+void do_build(const char *const *argv) {
+  static const char *const maintainerscripts[]= {
+    PREINSTFILE, POSTINSTFILE, PRERMFILE, POSTRMFILE, 0
+  };
+  
+  char *m;
+  const char *debar, *directory, *const *mscriptp;
+  char *controlfile;
+  struct pkginfo *checkedinfo;
+  struct arbitraryfield *field;
+  FILE *ar, *gz, *cf;
+  int p1[2],p2[2], warns, errs, n, c;
+  pid_t c1,c2,c3,c4,c5;
+  struct stat controlstab, datastab, mscriptstab;
+  char conffilename[MAXCONFFILENAME+1];
+  time_t thetime= 0;
+  
+  directory= *argv++; if (!directory) badusage("--build needs a directory argument");
+  if ((debar= *argv++) !=0) {
+    if (*argv) badusage("--build takes at most two arguments");
+  } else {
+    m= m_malloc(strlen(directory) + sizeof(DEBEXT));
+    strcpy(m,directory); strcat(m,DEBEXT);
+    debar= m;
+  }
+  
+  if (nocheckflag) {
+    printf(BACKEND ": warning, not checking contents of control area.\n"
+           BACKEND ": building an unknown package in `%s'.\n", debar);
+  } else {
+    controlfile= m_malloc(strlen(directory) + sizeof(BUILDCONTROLDIR) +
+                          sizeof(CONTROLFILE) + sizeof(CONFFILESFILE) +
+                          sizeof(POSTINSTFILE) + sizeof(PREINSTFILE) +
+                          sizeof(POSTRMFILE) + sizeof(PRERMFILE) +
+                          MAXCONFFILENAME + 5);
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/" CONTROLFILE);
+    warns= 0; errs= 0;
+    parsedb(controlfile, pdb_recordavailable|pdb_rejectstatus,
+            &checkedinfo, stderr, &warns);
+    assert(checkedinfo->available.valid);
+    if (checkedinfo->priority == pri_other) {
+      fprintf(stderr, "warning, `%s' contains user-defined Priority value `%s'\n",
+              controlfile, checkedinfo->otherpriority);
+      warns++;
+    }
+    for (field= checkedinfo->available.arbs; field; field= field->next) {
+      fprintf(stderr, "warning, `%s' contains user-defined field `%s'\n",
+              controlfile, field->name);
+      warns++;
+    }
+    checkversion(checkedinfo->available.version,"Version",&errs);
+    checkversion(checkedinfo->available.revision,"Revision",&errs);
+    if (errs) ohshit("%d errors in control file",errs);
+    printf(BACKEND ": building package `%s' in `%s'.\n", checkedinfo->name, debar);
+
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/");
+    if (lstat(controlfile,&mscriptstab)) ohshite("unable to stat control directory");
+    if (!S_ISDIR(mscriptstab.st_mode)) ohshit("control directory is not a directory");
+    if ((mscriptstab.st_mode & 07757) != 0755)
+      ohshit("control directory has bad permissions %03lo (must be >=0755 "
+             "and <=0775)", (unsigned long)(mscriptstab.st_mode & 07777));
+
+    for (mscriptp= maintainerscripts; *mscriptp; mscriptp++) {
+      strcpy(controlfile, directory);
+      strcat(controlfile, "/" BUILDCONTROLDIR "/");
+      strcat(controlfile, *mscriptp);
+
+      if (!lstat(controlfile,&mscriptstab)) {
+        if (S_ISLNK(mscriptstab.st_mode)) continue;
+        if (!S_ISREG(mscriptstab.st_mode))
+          ohshit("maintainer script `%.50s' is not a plain file or symlink",*mscriptp);
+        if ((mscriptstab.st_mode & 07557) != 0555)
+          ohshit("maintainer script `%.50s' has bad permissions %03lo "
+                 "(must be >=0555 and <=0775)",
+                 *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777));
+      } else if (errno != ENOENT) {
+        ohshite("maintainer script `%.50s' is not stattable",*mscriptp);
+      }
+    }
+
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/" CONFFILESFILE);
+    if ((cf= fopen(controlfile,"r"))) {
+      while (fgets(conffilename,MAXCONFFILENAME+1,cf)) {
+        n= strlen(conffilename);
+        if (!n) ohshite("empty string from fgets reading conffiles");
+        if (conffilename[n-1] != '\n') {
+          fprintf(stderr, "warning, conffile name `%.50s...' is too long", conffilename);
+          warns++;
+          while ((c= getc(cf)) != EOF && c != '\n');
+          continue;
+        }
+        conffilename[n-1]= 0;
+        strcpy(controlfile, directory);
+        strcat(controlfile, "/");
+        strcat(controlfile, conffilename);
+        if (lstat(controlfile,&controlstab)) {
+          if (errno == ENOENT)
+            ohshit("conffile `%.250s' does not appear in package",conffilename);
+          else
+            ohshite("conffile `%.250s' is not stattable",conffilename);
+        } else if (!S_ISREG(controlstab.st_mode)) {
+          fprintf(stderr, "warning, conffile `%s'"
+                  " is not a plain file\n", conffilename);
+          warns++;
+        }
+      }
+      if (ferror(cf)) ohshite("error reading conffiles file");
+      fclose(cf);
+    } else if (errno != ENOENT) {
+      ohshite("error opening conffiles file");
+    }
+    if (warns) {
+      if (fprintf(stderr, BACKEND ": ignoring %d warnings about the control"
+                  " file(s)\n", warns) == EOF) werr("stderr");
+    }
+  }
+  if (ferror(stdout)) werr("stdout");
+  
+  if (!(ar=fopen(debar,"wb"))) ohshite("unable to create `%.255s'",debar);
+  if (setvbuf(ar, 0, _IONBF, 0)) ohshite("unable to unbuffer `%.255s'",debar);
+  m_pipe(p1);
+  if (!(c1= m_fork())) {
+    m_dup2(p1[1],1); close(p1[0]); close(p1[1]);
+    if (chdir(directory)) ohshite("failed to chdir to `%.255s'",directory);
+    if (chdir(BUILDCONTROLDIR)) ohshite("failed to chdir to .../" BUILDCONTROLDIR);
+    execlp(TAR,"tar","-cf","-",".",(char*)0); ohshite("failed to exec tar -cf");
+  }
+  close(p1[1]);
+  if (!(gz= tmpfile())) ohshite("failed to make tmpfile (control)");
+  if (!(c2= m_fork())) {
+    m_dup2(p1[0],0); m_dup2(fileno(gz),1); close(p1[0]);
+    execlp(GZIP,"gzip","-9c",(char*)0); ohshite("failed to exec gzip -9c");
+  }
+  close(p1[0]);
+  waitsubproc(c2,"gzip -9c",0);
+  waitsubproc(c1,"tar -cf",0);
+  if (fstat(fileno(gz),&controlstab)) ohshite("failed to fstat tmpfile (control)");
+  if (oldformatflag) {
+    if (fprintf(ar, "%-8s\n%ld\n", OLDARCHIVEVERSION, (long)controlstab.st_size) == EOF)
+      werr(debar);
+  } else {
+    thetime= time(0);
+    if (fprintf(ar,
+                "!<arch>\n"
+                "debian-binary   %-12lu0     0     100644  %-10ld`\n"
+                ARCHIVEVERSION "\n"
+                "%s"
+                ADMINMEMBER "%-12lu0     0     100644  %-10ld`\n",
+                thetime,
+                (long)sizeof(ARCHIVEVERSION),
+                (sizeof(ARCHIVEVERSION)&1) ? "\n" : "",
+                (unsigned long)thetime,
+                (long)controlstab.st_size) == EOF)
+      werr(debar);
+  }                
+                
+  if (lseek(fileno(gz),0,SEEK_SET)) ohshite("failed to rewind tmpfile (control)");
+  if (!(c3= m_fork())) {
+    m_dup2(fileno(gz),0); m_dup2(fileno(ar),1);
+    execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat (control)");
+  }
+  waitsubproc(c3,"cat (control)",0);
+  
+  if (!oldformatflag) {
+    fclose(gz);
+    if (!(gz= tmpfile())) ohshite("failed to make tmpfile (data)");
+  }
+  m_pipe(p2);
+  if (!(c4= m_fork())) {
+    m_dup2(p2[1],1); close(p2[0]); close(p2[1]);
+    if (chdir(directory)) ohshite("failed to chdir to `%.255s'",directory);
+    execlp(TAR,"tar","--exclude",BUILDCONTROLDIR,"-cf","-",".",(char*)0);
+    ohshite("failed to exec tar --exclude");
+  }
+  close(p2[1]);
+  if (!(c5= m_fork())) {
+    m_dup2(p2[0],0); close(p2[0]);
+    m_dup2(oldformatflag ? fileno(ar) : fileno(gz),1);
+    execlp(GZIP,"gzip","-9c",(char*)0);
+    ohshite("failed to exec gzip -9c from tar --exclude");
+  }
+  close(p2[0]);
+  waitsubproc(c5,"gzip -9c from tar --exclude",0);
+  waitsubproc(c4,"tar --exclude",0);
+  if (!oldformatflag) {
+    if (fstat(fileno(gz),&datastab)) ohshite("failed to fstat tmpfile (data)");
+    if (fprintf(ar,
+                "%s"
+                DATAMEMBER "%-12lu0     0     100644  %-10ld`\n",
+                (controlstab.st_size & 1) ? "\n" : "",
+                (unsigned long)thetime,
+                (long)datastab.st_size) == EOF)
+      werr(debar);
+
+    if (lseek(fileno(gz),0,SEEK_SET)) ohshite("failed to rewind tmpfile (data)");
+    if (!(c3= m_fork())) {
+      m_dup2(fileno(gz),0); m_dup2(fileno(ar),1);
+      execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat (data)");
+    }
+    waitsubproc(c3,"cat (data)",0);
+
+    if (datastab.st_size & 1)
+      if (putc('\n',ar) == EOF)
+        werr(debar);
+  }
+  if (fclose(ar)) werr(debar);
+                             
+  exit(0);
+}
+
diff --git a/dpkg-deb/debugmake b/dpkg-deb/debugmake
new file mode 100755 (executable)
index 0000000..638c74d
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make XCFLAGS='-g -O0' LDFLAGS=-g LIBS='-lefence -L../lib -ldpkg' "$@"
diff --git a/dpkg-deb/dpkg-deb.8 b/dpkg-deb/dpkg-deb.8
new file mode 100644 (file)
index 0000000..b9af3dd
--- /dev/null
@@ -0,0 +1,130 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Authors: Raul Miller and Ian Jackson
+.TH DPKG\-DEB 8 "29 Nov 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME 
+dpkg\-deb \- Debian GNU/Linux package archive backend
+.SH SYNOPSIS
+.B dpkg-deb --version
+.LP
+.B dpkg-deb
+.BR -X | --vextract
+.I <deb>
+.RI [ <directory> ]
+.LP
+.B dpkg-deb
+.BR -b | --build
+.RB [ --nocheck ]
+.I <directory>
+.RI [ <deb> ]
+.LP
+.B dpkg-deb
+.BR -c | --contents
+.I <deb>
+.LP
+.B dpkg-deb
+.BR -e | --control
+.I <deb>
+.RI [ <directory> ]
+.LP
+.B dpkg-deb
+.BR -f | --field
+.I <deb>
+.RI [ <cfield> ]...
+.LP
+.B dpkg-deb
+.BR -h | --help
+.LP
+.B dpkg-deb
+.BR -I | --info
+.I <deb>
+.RI [ <cfile> ]
+.LP
+.B dpkg-deb
+.BR -x | --extract 
+.I <deb> <directory>
+.LP
+.B dpkg-deb
+.BR -D | --debug
+.I <invocation-options>
+.SH DESCRIPTION
+.B dpkg-deb
+packs and unpacks debian archives.  It tracks file permissions, and
+includes support for the staged unpacking mechanism required by debian.
+.SH OPTIONS
+.I <deb>
+is the filename of a Debian format archive.
+.I <cfile>
+is the name of an administrative file component.
+.I <cfield>
+is the name of a field in the main `control' file.
+.LP
+.B --version
+displays the version number.
+.LP
+.BR -X | --vextract
+extracts files from archive and lists archive's contents.
+.LP
+.BR -b | --build
+makes a debian archive from the image of
+.IR <directory> .
+.I <directory>
+must have a
+.B DEBIAN
+subdirectory, which is treated specially for the debian-specific
+control file and any pre- or post-install scripts.
+
+The
+.B DEBIAN
+directory must contain a file called
+.B control
+whose contents is a valid control file for the Debian package
+management system.  Errors in this file will abort the processing of
+the package.  This check can be bypassed by the use of the
+.B --nocheck
+option.
+.LP
+.BR -c | --contents
+lists the contents of the archive on stdout.
+.LP
+.BR -e | --control
+extracts the control file from the archive.
+If no target directory is specified, the control files are extracted
+into
+.BR ./DEBIAN .
+.LP
+.BR -f | --field
+displays [named field(s) from] the control file.
+.LP
+.BR -h | --help
+displays summary of usage.
+.LP
+.BR -I | --info
+describes the archive, on stdout.
+.LP
+.BR -x | --extract
+extracts files from archive.
+.LP
+.BR -D | --debug
+would enable debugging.
+.SH NOTES
+.B dpkg-deb
+packs and unpacks *.deb files, but does not deal with any of the
+larger administrative issues of installing/de-installing packages.
+.SH SEE ALSO
+.BR deb (5),
+.BR deb-control (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dselect (8).
+.SH BUGS
+.B dpkg-deb -I 
+.IB package1 .deb
+.IB package2 .deb
+does the wrong thing.
+
+This manpage is too terse and fails to document all the options.  If
+you are a competent and accurate writer and are willing to spend the
+time reading the source and writing good manpages please
+please write a better man page than this one.
+.LP
+Still being developed, as of 29th November 1995.
diff --git a/dpkg-deb/dpkg-deb.8-vuori b/dpkg-deb/dpkg-deb.8-vuori
new file mode 100644 (file)
index 0000000..ca22395
--- /dev/null
@@ -0,0 +1,133 @@
+.TH dpkg-deb 8
+.SH NAME
+dpkg-deb - a low-level package manager for Debian GNU/Linux
+
+.SH SYNOPSIS
+
+.B dpkb-deb
+[options] action
+
+.SH DESCRIPTION
+
+.B Dpkg-deb
+is a low-level tool to build, and manage Debian GNU/Linux packages.
+The dpkg-deb is intended to be used via
+.B dpkg(8)
+tool. The actions described here can be given to
+.B dpkg
+also. What
+.B dpkg
+actually does with them is that it runs
+.B dpkg-deb
+with those parameters. However, using
+.B dpkg
+instead of
+.B dpkg-deb
+is a better idea, for it can be used more generally with all Debian
+package handling.
+
+dpkg-deb is operated via two different types of command
+line parameters: actions and options. The actions tell dpkg-deb what
+to do and options control the behaviour of the action in some way.
+
+.SS ACTIONS
+
+.TP
+.B dpkg-deb -b|--build <directory> [<filename>]
+Build a Debian package named
+.I <filename>
+from files in
+.I <directory>.
+If filename is not specified, a file called
+.I <directory>.deb
+is created instead. The directory
+.I <directory>/DEBIAN
+must contain a special file named 
+.I control
+and may optionally contain other control files too.
+See
+.B deb(5)
+for more information about those files.
+.TP
+.B dpkg-deb -I|--info <filename> [<control-file>...]
+Show information about a package named
+.I <filename>.
+By default this command shows the control-file of this package (see
+.B deb-control(5)
+) and some statistics (file lengths, etc.). If
+.I <control-file>
+is specified, the specified file is displayed instead. See
+.B deb(5)
+for more information about control-files.
+.TP
+.B dpkg-deb -c|--contents <filename>
+List contents of Debian GNU/Linux package
+.I <filename>.
+.TP
+.B dpkg-deb -e|--control <filename> [<directory>]
+Extract control-information from a package named
+.I <filename>.
+This action creates a directory named
+.I <directory>,
+or if it isn't specified, a directory named
+.I DEBIAN,
+containing control files of specified package. See
+.B deb(5)
+for more information about those files.
+.TP
+.B dpkg-deb -f|--field <filename> [<control-field>]
+Display control field(s) of a package
+.I <filename>.
+By default all fields are displayed. See
+.B deb-control(5)
+for more information about these fields.
+.TP
+.B dpkg-deb --fsys-tarfile <filename>
+Display the filesystem tar-file contained by a Debian package
+.I <filename>.
+This tar-file is the file that is extracted to
+.I /
+while the package is installed.
+.TP
+.B dpkg-deb -X|--vextract | -x|--extract <filename> <directory>
+Extract the files contained by a package named
+.I <filename>
+to
+.I <directory>.
+.B --vextract
+also displays the names of files contained by the package.
+.TP
+.B dpkg-deb --help|-h
+Type a brief help.
+.TP
+.B dpkg-deb --licence
+Type licence of
+.B dpkg-deb.
+.TP
+.B dpkg-deb --version
+Type version information.
+
+
+.SS OPTIONS
+
+.TP
+.B -D | --debug
+Set debugging on.
+.TP
+.B --new | --old
+Select new or old package format. The default format is old.
+
+.SH SEE ALSO
+.B deb(5)
+,
+.B dpkg-deb(8)
+,
+.B dselect(8)
+and
+.B deb-control(5)
+
+.SH AUTHOR
+.B dpkg
+is written by Ian Jackson (ian@chiark.chu.cam.ac.uk). Manual page added
+by Juho Vuori (javuori@cc.helsinki.fi).
+
diff --git a/dpkg-deb/dpkg-deb.h b/dpkg-deb/dpkg-deb.h
new file mode 100644 (file)
index 0000000..946e823
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * dpkg-deb.h - external definitions for this program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_DEB_H
+#define DPKG_DEB_H
+
+typedef void dofunction(const char *const *argv);
+dofunction do_build, do_contents, do_control;
+dofunction do_info, do_field, do_extract, do_vextract, do_fsystarfile;
+
+extern int debugflag, nocheckflag, oldformatflag;
+extern const struct cmdinfo *cipaction;
+extern dofunction *action;
+
+void extracthalf(const char *debar, const char *directory,
+                 const char *taroption, int admininfo);
+
+#define DEBMAGIC     "!<arch>\ndebian-binary   "
+#define ADMINMEMBER  "control.tar.gz  "
+#define DATAMEMBER   "data.tar.gz     "
+
+#endif /* DPKG_DEB_H */
diff --git a/dpkg-deb/extract.c b/dpkg-deb/extract.c
new file mode 100644 (file)
index 0000000..8c9327f
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * extract.c - extracting archives
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+#include <ar.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-deb.h"
+#include "myopt.h"
+
+static void movecontrolfiles(const char *thing) {
+  char buf[200];
+  pid_t c1;
+  
+  sprintf(buf, "mv %s/* . && rmdir %s", thing, thing);
+  if (!(c1= m_fork())) {
+    execlp("sh","sh","-c",buf,(char*)0); ohshite("failed to exec sh -c mv foo/* &c");
+  }
+  waitsubproc(c1,"sh -c mv foo/* &c",0);
+}
+
+static void readfail(FILE *a, const char *filename, const char *what) {
+  if (ferror(a)) {
+    ohshite("error reading %s from %.255s",what,filename);
+  } else {
+    ohshit("unexpected end of file in %s in %.255s",what,filename);
+  }
+}
+
+static unsigned long parseheaderlength(const char *inh, size_t len,
+                                       const char *fn, const char *what) {
+  char lintbuf[15];
+  unsigned long r;
+  char *endp;
+
+  if (memchr(inh,0,len))
+    ohshit("file `%.250s' is corrupt - %.250s length contains nulls",fn,what);
+  assert(sizeof(lintbuf) > len);
+  memcpy(lintbuf,inh,len);
+  lintbuf[len]= ' ';
+  *strchr(lintbuf,' ')= 0;
+  r= strtoul(lintbuf,&endp,10);
+  if (*endp)
+    ohshit("file `%.250s' is corrupt - bad digit (code %d) in %s",fn,*endp,what);
+  return r;
+}
+
+static void skipmember(FILE *ar, const char *fn, long memberlen) {
+  int c;
+  
+  memberlen += (memberlen&1);
+  while (memberlen > 0) {
+    if ((c= getc(ar)) == EOF) readfail(ar,fn,"skipped member data");
+    memberlen--;
+  }
+}
+
+void extracthalf(const char *debar, const char *directory,
+                 const char *taroption, int admininfo) {
+  char versionbuf[40];
+  float versionnum;
+  char ctrllenbuf[40], *infobuf;
+  long ctrllennum, memberlen= 0;
+  int dummy, l= 0;
+  pid_t c1=0,c2,c3;
+  unsigned char *ctrlarea= 0;
+  int p1[2], p2[2];
+  FILE *ar, *pi;
+  struct stat stab;
+  char nlc;
+  char *cur;
+  struct ar_hdr arh;
+  int readfromfd, oldformat, header_done, adminmember, c;
+  
+  ar= fopen(debar,"r"); if (!ar) ohshite("failed to read archive `%.255s'",debar);
+  if (fstat(fileno(ar),&stab)) ohshite("failed to fstat archive");
+  if (!fgets(versionbuf,sizeof(versionbuf),ar)) readfail(ar,debar,"version number");
+
+  if (!strcmp(versionbuf,"!<arch>\n")) {
+    oldformat= 0;
+
+    ctrllennum= 0;
+    header_done= 0;
+    for (;;) {
+      if (fread(&arh,1,sizeof(arh),ar) != sizeof(arh))
+        readfail(ar,debar,"between members");
+      if (memcmp(arh.ar_fmag,ARFMAG,sizeof(arh.ar_fmag)))
+        ohshit("file `%.250s' is corrupt - bad magic at end of first header",debar);
+      memberlen= parseheaderlength(arh.ar_size,sizeof(arh.ar_size),
+                                   debar,"member length");
+      if (memberlen<0)
+        ohshit("file `%.250s' is corrupt - negative member length %ld",debar,memberlen);
+      if (!header_done) {
+        if (memcmp(arh.ar_name,"debian-binary   ",sizeof(arh.ar_name)))
+          ohshit("file `%.250s' is not a debian binary archive (try dpkg-split?)",debar);
+        infobuf= m_malloc(memberlen+1);
+        if (fread(infobuf,1, memberlen + (memberlen&1), ar) != memberlen + (memberlen&1))
+          readfail(ar,debar,"header info member");
+        infobuf[memberlen]= 0;
+        cur= strchr(infobuf,'\n');
+        if (!cur) ohshit("archive has no newlines in header");
+        *cur= 0;
+        cur= strchr(infobuf,'.');
+        if (!cur) ohshit("archive has no dot in version number");
+        *cur= 0;
+        if (strcmp(infobuf,"2"))
+          ohshit("archive version %.250s not understood, get newer " BACKEND, infobuf);
+        *cur= '.';
+        strncpy(versionbuf,infobuf,sizeof(versionbuf));
+        versionbuf[sizeof(versionbuf)-1]= 0;
+        header_done= 1;
+      } else if (arh.ar_name[0] == '_') {
+          /* Members with `_' are noncritical, and if we don't understand them
+           * we skip them.
+           */
+        skipmember(ar,debar,memberlen);
+      } else {
+        adminmember=
+          !memcmp(arh.ar_name,ADMINMEMBER,sizeof(arh.ar_name)) ? 1 :
+          !memcmp(arh.ar_name,DATAMEMBER,sizeof(arh.ar_name)) ? 0 :
+          -1;
+        if (adminmember == -1) {
+          ohshit("file `%.250s' contains ununderstood data member %.*s, giving up",
+                 debar, (int)sizeof(arh.ar_name), arh.ar_name);
+        }
+        if (adminmember == 1) {
+          if (ctrllennum != 0)
+            ohshit("file `%.250s' contains two control members, giving up", debar);
+          ctrllennum= memberlen;
+        }
+        if (!adminmember != !admininfo) {
+          skipmember(ar,debar,memberlen);
+        } else {
+          break; /* Yes ! - found it. */
+        }
+      }
+    }
+
+    if (admininfo >= 2)
+      if (printf(" new debian package, version %s.\n"
+                 " size %ld bytes: control archive= %ld bytes.\n",
+                 versionbuf, (long)stab.st_size, ctrllennum) == EOF ||
+          fflush(stdout)) werr("stdout");
+    
+  } else if (!strncmp(versionbuf,"0.93",4) &&
+             sscanf(versionbuf,"%f%c%d",&versionnum,&nlc,&dummy) == 2 &&
+             nlc == '\n') {
+    
+    oldformat= 1;
+    l= strlen(versionbuf); if (l && versionbuf[l-1]=='\n') versionbuf[l-1]=0;
+    if (!fgets(ctrllenbuf,sizeof(ctrllenbuf),ar))
+      readfail(ar,debar,"ctrl information length");
+    if (sscanf(ctrllenbuf,"%ld%c%d",&ctrllennum,&nlc,&dummy) !=2 || nlc != '\n')
+      ohshit("archive has malformatted ctrl len `%s'",ctrllenbuf);
+
+    if (admininfo >= 2)
+      if (printf(" old debian package, version %s.\n"
+                 " size %ld bytes: control archive= %ld, main archive= %ld.\n",
+                 versionbuf, (long)stab.st_size, ctrllennum,
+                 (long) (stab.st_size - ctrllennum - strlen(ctrllenbuf) - l)) == EOF ||
+          fflush(stdout)) werr("stdout");
+    
+    ctrlarea= malloc(ctrllennum); if (!ctrlarea) ohshite("malloc ctrlarea failed");
+
+    errno=0; if (fread(ctrlarea,1,ctrllennum,ar) != ctrllennum)
+      readfail(ar,debar,"ctrlarea");
+
+  } else {
+    ohshit("`%.255s' is not a debian format archive",debar);
+  }
+
+  fflush(ar);
+  if (oldformat) {
+    if (admininfo) {
+      m_pipe(p1);
+      if (!(c1= m_fork())) {
+        close(p1[0]);
+        if (!(pi= fdopen(p1[1],"w"))) ohshite("failed to fdopen p1 in paste");
+        errno=0; if (fwrite(ctrlarea,1,ctrllennum,pi) != ctrllennum)
+          ohshit("failed to write to gzip -dc");
+        if (fclose(pi)) ohshit("failed to close gzip -dc");
+        exit(0);
+      }
+      close(p1[1]);
+      readfromfd= p1[0];
+    } else {
+      if (lseek(fileno(ar),l+strlen(ctrllenbuf)+ctrllennum,SEEK_SET) == -1)
+        ohshite("failed to syscall lseek to files archive portion");
+      c1= -1;
+      readfromfd= fileno(ar);
+    }
+  } else {
+    m_pipe(p1);
+    if (!(c1= m_fork())) {
+      close(p1[0]);
+      if (!(pi= fdopen(p1[1],"w"))) ohshite("failed to fdopen p1 in copy");
+      while (memberlen > 0) {
+        if ((c= getc(ar)) == EOF) readfail(ar,debar,"member data");
+        if (putc(c,pi) == EOF) ohshite("failed to write to pipe in copy");
+        memberlen--;
+      }
+      if (fclose(pi) == EOF) ohshite("failed to close pipe in copy");
+      exit(0);
+    }
+    close(p1[1]);
+    readfromfd= p1[0];
+  }
+  
+  if (taroption) m_pipe(p2);
+  
+  if (!(c2= m_fork())) {
+    m_dup2(readfromfd,0);
+    if (admininfo) close(p1[0]);
+    if (taroption) { m_dup2(p2[1],1); close(p2[0]); close(p2[1]); }
+    execlp(GZIP,"gzip","-dc",(char*)0); ohshite("failed to exec gzip -dc");
+  }
+  if (readfromfd != fileno(ar)) close(readfromfd);
+  close(p2[1]);
+
+  if (taroption && directory) {
+    if (chdir(directory)) {
+      if (errno == ENOENT) {
+        if (mkdir(directory,0777)) ohshite("failed to create directory");
+        if (chdir(directory)) ohshite("failed to chdir to directory after creating it");
+      } else {
+        ohshite("failed to chdir to directory");
+      }
+    }
+  }
+
+  if (taroption) {
+    if (!(c3= m_fork())) {
+      char buffer[30+2];
+      if(strlen(taroption) > 30) internerr(taroption);
+      strcpy(buffer, taroption);
+      strcat(buffer, "f");
+      m_dup2(p2[0],0);
+      execlp(TAR,"tar",buffer,"-",(char*)0);
+      ohshite("failed to exec tar");
+    }
+    close(p2[0]);
+    waitsubproc(c3,"tar",0);
+  }
+  
+  waitsubproc(c2,"gzip -dc",1);
+  if (c1 != -1) waitsubproc(c1,"paste",0);
+  if (oldformat && admininfo) {
+    if (versionnum == 0.931F) {
+      movecontrolfiles(OLDOLDDEBDIR);
+    } else if (versionnum == 0.932F || versionnum == 0.933F) {
+      movecontrolfiles(OLDDEBDIR);
+    }
+  }
+}
+
+static void controlextractvextract(int admin,
+                                   const char *taroptions,
+                                   const char *const *argv) {
+  const char *debar, *directory;
+  
+  if (!(debar= *argv++))
+    badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (!(directory= *argv++)) {
+    if (admin) directory= EXTRACTCONTROLDIR;
+    else ohshit("--%s needs a target directory.\n"
+                "Perhaps you should be using " DPKG " --install ?",cipaction->olong);
+  } else if (*argv) {
+    badusage("--%s takes at most two arguments (.deb and directory",cipaction->olong);
+  }
+  extracthalf(debar, directory, taroptions, admin);
+}
+
+void do_fsystarfile(const char *const *argv) {
+  const char *debar;
+  
+  if (!(debar= *argv++))
+    badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (*argv)
+    badusage("--%s takes only one argument (.deb filename)",cipaction->olong);
+  extracthalf(debar,0,0,0);
+}
+   
+void do_control(const char *const *argv) { controlextractvextract(1, "x", argv); }
+void do_extract(const char *const *argv) { controlextractvextract(0, "xp", argv); }
+void do_vextract(const char *const *argv) { controlextractvextract(0, "xpv", argv); }
diff --git a/dpkg-deb/info.c b/dpkg-deb/info.c
new file mode 100644 (file)
index 0000000..987a05b
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * info.c - providing information
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-deb.h"
+#include "myopt.h"
+
+static void cu_info_prepare(int argc, void **argv) {
+  pid_t c1;
+  int status;
+  char *directory;
+  struct stat stab;
+
+  directory= (char*)(argv[0]);
+  if (chdir("/")) { perror("failed to chdir to `/' for cleanup"); return; }
+  if (lstat(directory,&stab) && errno==ENOENT) return;
+  if ((c1= fork()) == -1) { perror("failed to fork for cleanup"); return; }
+  if (!c1) {
+    execlp(RM,"rm","-r",directory,(char*)0);
+    perror("failed to exec " RM " for cleanup"); _exit(1);
+  }
+  if (waitpid(c1,&status,0) != c1) { perror("failed to wait for rm cleanup"); return; }
+  if (status) { fprintf(stderr,"rm cleanup failed, code %d\n",status); }
+} 
+
+static void info_prepare(const char *const **argvp,
+                         const char **debarp,
+                         const char **directoryp,
+                         int admininfo) {
+  static char dbuf[L_tmpnam];
+  pid_t c1;
+  
+  *debarp= *(*argvp)++;
+  if (!*debarp) badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (!tmpnam(dbuf)) ohshite("failed to make temporary filename");
+  *directoryp= dbuf;
+
+  if (!(c1= m_fork())) {
+    execlp(RM,"rm","-rf",dbuf,(char*)0); ohshite("failed to exec rm -rf");
+  }
+  waitsubproc(c1,"rm -rf",0);
+  push_cleanup(cu_info_prepare,-1, 0,0, 1, (void*)dbuf);
+  extracthalf(*debarp, dbuf, "mx", admininfo);
+}
+
+static int ilist_select(const struct dirent *de) {
+  return strcmp(de->d_name,".") && strcmp(de->d_name,"..");
+}
+
+static void info_spew(const char *debar, const char *directory,
+                      const char *const *argv) {
+  const char *component;
+  FILE *co;
+  pid_t c1;
+  int re= 0;
+
+  while ((component= *argv++) != 0) {
+    co= fopen(component,"r");
+    if (co) {
+      if (!(c1= m_fork())) {
+        m_dup2(fileno(co),0);
+        execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat component");
+      }
+      waitsubproc(c1,"cat component",0);
+    } else if (errno == ENOENT) {
+      if (fprintf(stderr, BACKEND ": `%.255s' contains no control component `%.255s'\n",
+                  debar, component) == EOF) werr("stderr");
+      re= 1;
+    } else {
+      ohshite("open component `%.255s' (in %.255s) failed in an unexpected way",
+              component, directory);
+    }
+  }
+  if (re) ohshit("at least one requested control component missing");
+}
+
+static void info_list(const char *debar, const char *directory) {
+  char interpreter[INTERPRETER_MAX+1], *p;
+  int il, lines;
+  struct dirent **cdlist, *cdep;
+  int cdn;
+  FILE *cc;
+  struct stat stab;
+  int c;
+
+  cdn= scandir(".", &cdlist, &ilist_select, alphasort);
+  if (cdn == -1) ohshite("cannot scan directory `%.255s'",directory);
+
+  while (cdn-- >0) {
+    cdep= *cdlist++;
+    if (stat(cdep->d_name,&stab))
+      ohshite("cannot stat `%.255s' (in `%.255s')",cdep->d_name,directory);
+    if (S_ISREG(stab.st_mode)) {
+      if (!(cc= fopen(cdep->d_name,"r")))
+        ohshite("cannot open `%.255s' (in `%.255s')",cdep->d_name,directory);
+      lines= 0; interpreter[0]= 0;
+      if ((c= getc(cc))== '#') {
+        if ((c= getc(cc))== '!') {
+          while ((c= getc(cc))== ' ');
+          p=interpreter; *p++='#'; *p++='!'; il=2;
+          while (il<INTERPRETER_MAX && !isspace(c) && c!=EOF) {
+            *p++= c; il++; c= getc(cc);
+          }
+          *p++= 0;
+          if (c=='\n') lines++;
+        }
+      }
+      while ((c= getc(cc))!= EOF) { if (c == '\n') lines++; }
+      if (ferror(cc)) ohshite("failed to read `%.255s' (in `%.255s')",
+                              cdep->d_name,directory);
+      fclose(cc);
+      if (printf(" %7ld bytes, %5d lines   %c  %-20.127s %.127s\n",
+                 (long)stab.st_size, lines,
+                 S_IXUSR & stab.st_mode ? '*' : ' ',
+                 cdep->d_name, interpreter) == EOF)
+        werr("stdout");
+    } else {
+      if (printf("     not a plain file          %.255s\n",cdep->d_name) == EOF)
+        werr("stdout");
+    }
+  }
+  if (!(cc= fopen("control","r"))) {
+    if (errno != ENOENT) ohshite("failed to read `control' (in `%.255s')",directory);
+    if (!fputs("(no `control' file in control archive!)\n",stdout)) werr("stdout");
+  } else {
+    lines= 1;
+    while ((c= getc(cc))!= EOF) {
+      if (lines) if (putc(' ',stdout) == EOF) werr("stdout");
+      if (putc(c,stdout) == EOF) werr("stdout");
+      lines= c=='\n';
+    }
+    if (!lines) if (putc('\n',stdout) == EOF) werr("stdout");
+  }
+}
+
+static void info_field(const char *debar, const char *directory,
+                       const char *const *fields, int showfieldname) {
+  FILE *cc;
+  char fieldname[MAXFIELDNAME+1];
+  char *pf;
+  const char *const *fp;
+  int doing, c, lno, fnl;
+
+  if (!(cc= fopen("control","r"))) ohshite("could not open the `control' component");
+  doing= 1; lno= 1;
+  for (;;) {
+    c= getc(cc);  if (c==EOF) { doing=0; break; }
+    if (c == '\n') { lno++; doing=1; continue; }
+    if (!isspace(c)) {
+      doing= 0;
+      for (pf=fieldname, fnl=0;
+           fnl <= MAXFIELDNAME && c!=EOF && !isspace(c) && c!=':';
+           c= getc(cc)) { *pf++= c; fnl++; }
+      *pf++= 0;
+      doing= fnl >= MAXFIELDNAME || c=='\n' || c==EOF;
+      for (fp=fields; !doing && *fp; fp++)
+        if (!strcasecmp(*fp,fieldname)) doing=1;
+      if (showfieldname) {
+        if (doing)
+          fputs(fieldname,stdout);
+      } else {
+        if (c==':') c= getc(cc);
+        while (c != '\n' && isspace(c)) c= getc(cc);
+      }
+    }
+    for(;;) {
+      if (c == EOF) break;
+      if (doing) putc(c,stdout);
+      if (c == '\n') { lno++; break; }
+      c= getc(cc);
+    }
+    if (c == EOF) break;
+  }
+  if (ferror(cc)) ohshite("failed during read of `control' component");
+  if (doing) putc('\n',stdout);
+  if (ferror(stdout)) werr("stdout");
+}
+
+void do_info(const char *const *argv) {
+  const char *debar, *directory;
+
+  if (*argv && argv[1]) {
+    info_prepare(&argv,&debar,&directory,1);
+    info_spew(debar,directory, argv);
+  } else {
+    info_prepare(&argv,&debar,&directory,2);
+    info_list(debar,directory);
+  }
+}
+
+void do_field(const char *const *argv) {
+  const char *debar, *directory;
+
+  info_prepare(&argv,&debar,&directory,1);
+  if (*argv) {
+    info_field(debar, directory, argv, argv[1]!=0);
+  } else {
+    static const char *const controlonly[]= { "control", 0 };
+    info_spew(debar,directory, controlonly);
+  }
+}
+
+void do_contents(const char *const *argv) {
+  const char *debar;
+  
+  if (!(debar= *argv++) || *argv) badusage("--contents takes exactly one argument");
+  extracthalf(debar, 0, "tv", 0);
+}
diff --git a/dpkg-deb/main.c b/dpkg-deb/main.c
new file mode 100644 (file)
index 0000000..0804ac7
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * main.c - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "version.h"
+#include "myopt.h"
+#include "dpkg-deb.h"
+
+static void printversion(void) {
+  if (!fputs("Debian GNU/Linux `" BACKEND "' package archive backend "
+             "version " DPKG_VERSION_ARCH ".\n"
+             "Copyright (C) 1994,1995 Ian Jackson.  This is free software; see the\n"
+             "GNU General Public Licence version 2 or later for copying conditions.\n"
+             "There is NO warranty.  See dpkg-deb --licence for details.\n",
+             stderr)) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs("\
+Usage: " BACKEND " -b|--build <directory> [<deb>]    Build an archive.\n\
+       " BACKEND " -c|--contents <deb>               List contents.\n\
+       " BACKEND " -I|--info <deb> [<cfile>...]      Show info to stdout.\n\
+       " BACKEND " -f|--field <deb> [<cfield>...]    Show field(s) to stdout.\n\
+       " BACKEND " -e|--control <deb> [<directory>]  Extract control info.\n\
+       " BACKEND " -x|--extract <deb> <directory>    Extract files.\n\
+       " BACKEND " -X|--vextract <deb> <directory>   Extract & list files.\n\
+       " BACKEND " --fsys-tarfile <deb>              Output filesystem tarfile.\n\
+       " BACKEND " -h|--help                         Display this message.\n\
+       " BACKEND " --version | --licence             Show version/licence.\n\
+<deb> is the filename of a Debian format archive.\n\
+<cfile> is the name of an administrative file component.\n\
+<cfield> is the name of a field in the main `control' file.\n\
+Options:  -D for debugging output; --old or --new controls archive format;\n\
+          --no-check to suppress control file check (build bad package).\n\
+\n\
+Use `" DPKG "' to install and remove packages from your system, or\n\
+`" DSELECT "' for user-friendly package management.  Packages unpacked\n\
+using `" BACKEND " --extract' will be incorrectly installed !\n",
+             stderr)) werr("stderr");
+}
+
+const char thisname[]= BACKEND;
+const char printforhelp[]=
+ "Type " BACKEND " --help for help about manipulating *.deb files;\n"
+ "Type " DPKG " --help for help about installing and deinstalling packages.";
+
+int debugflag=0, nocheckflag=0, oldformatflag=BUILDOLDPKGFORMAT;
+const struct cmdinfo *cipaction=0;
+dofunction *action=0;
+
+static void helponly(const struct cmdinfo *cip, const char *value) {
+  usage(); exit(0);
+}
+static void versiononly(const struct cmdinfo *cip, const char *value) {
+  printversion(); exit(0);
+}
+
+static void setaction(const struct cmdinfo *cip, const char *value);
+
+static dofunction *const dofunctions[]= {
+  do_build,
+  do_contents,
+  do_control,
+  do_info,
+  do_field,
+  do_extract,
+  do_vextract,
+  do_fsystarfile
+};
+
+/* NB: the entries using setaction must appear first and be in the
+ * same order as dofunctions:
+ */
+static const struct cmdinfo cmdinfos[]= {
+  { "build",        'b',  0,  0, 0,               setaction        },
+  { "contents",     'c',  0,  0, 0,               setaction        },
+  { "control",      'e',  0,  0, 0,               setaction        },
+  { "info",         'I',  0,  0, 0,               setaction        },
+  { "field",        'f',  0,  0, 0,               setaction        },
+  { "extract",      'x',  0,  0, 0,               setaction        },
+  { "vextract",     'X',  0,  0, 0,               setaction        },
+  { "fsys-tarfile",  0,   0,  0, 0,               setaction        },
+  { "new",           0,   0,  &oldformatflag, 0,  0,            0  },
+  { "old",           0,   0,  &oldformatflag, 0,  0,            1  },
+  { "debug",        'D',  0,  &debugflag,     0,  0,            1  },
+  { "nocheck",       0,   0,  &nocheckflag,   0,  0,            1  },
+  { "help",         'h',  0,  0, 0,               helponly         },
+  { "version",       0,   0,  0, 0,               versiononly      },
+  { "licence",       0,   0,  0, 0,               showcopyright    }, /* UK spelling */
+  { "license",       0,   0,  0, 0,               showcopyright    }, /* US spelling */
+  {  0,              0                                             }
+};
+
+static void setaction(const struct cmdinfo *cip, const char *value) {
+  if (cipaction)
+    badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong);
+  cipaction= cip;
+  assert(cip-cmdinfos < sizeof(dofunctions)*sizeof(dofunction*));
+  action= dofunctions[cip-cmdinfos];
+}
+
+int main(int argc, const char *const *argv) {
+  jmp_buf ejbuf;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  myopt(&argv,cmdinfos);
+  if (!cipaction) badusage("need an action option");
+
+  unsetenv("GZIP");
+  action(argv);
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+  exit(0);
+}
diff --git a/dpkg-deb/mkdeb.sh b/dpkg-deb/mkdeb.sh
new file mode 100644 (file)
index 0000000..146dd53
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+# This script is only supposed to be called by dpkg-deb.
+# Its arguments are: <sourcefile> <partsize> <prefix> <totalsize>
+# Stdin is also redirected from the source archive by dpkg-split.
+
+# Copyright (C) 1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+set -e
+
+if [ "$#" != 4 ]; then echo >&2 'Bad invocation of mksplit.sh.'; exit 1; fi
+
+sourcefile="$1"
+partsize="$2"
+prefix="$3"
+orgsize="$4"
+
+myversion=2.0
+binary=i386-linux
+#csum=`md5sum <"$sourcefile"`
+#package="`dpkg-deb --field \"$sourcefile\" Package`"
+#version="`dpkg-deb --field \"$sourcefile\" Version`"
+#revision="`dpkg-deb --field \"$sourcefile\" Package_Revision`"
+startat=0
+partnum=0
+
+mkdir /tmp/ds$$
+ec=1
+trap "rm -r /tmp/ds$$; exit $ec" 0
+dsp=/tmp/ds$$/debian-binary
+
+echo -n "Splitting package $package into $nparts parts: "
+
+while [ $startat -lt $orgsize ]
+do
+       showpartnum=$[$partnum+1]
+       echo $myversion >$dsp
+       echo $binary >>$dsp
+       tar -C DEBIAN -cf /tmp/ds$$/control .
+       tar --
+       dd bs=$partsize skip=$partnum count=1 \
+          of=/tmp/ds$$/data.$showpartnum \
+        2>&1 | (egrep -v '.* records (in|out)' || true)
+       rm -f /tmp/ds$$/part
+       echo -n "$showpartnum "
+       (cd /tmp/ds$$ &&
+        ar qc part debian-split data.$showpartnum)
+       mv /tmp/ds$$/part $prefix.${showpartnum}of$nparts.deb
+       startat=$[$startat+$partsize]
+       partnum=$showpartnum
+done
+echo "done"
+
+ec=0
diff --git a/dselect/Makefile.in b/dselect/Makefile.in
new file mode 100644 (file)
index 0000000..1ef6f9c
--- /dev/null
@@ -0,0 +1,119 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+
+SRC =                                                                       \
+ main.cc        bindings.cc    curkeys.cc     helpmsgs.cc                   \
+ basecmds.cc    baselist.cc    basetop.cc                                   \
+ pkgcmds.cc     pkgdepcon.cc   pkgdisplay.cc  pkginfo.cc     pkgkeys.cc     \
+ pkglist.cc     pkgsublist.cc  pkgtop.cc                                    \
+ methkeys.cc    method.cc      methparse.cc   methlist.cc
+
+OBJ =                                                                       \
+ main.o         bindings.o     curkeys.o      helpmsgs.o                    \
+ basecmds.o     baselist.o     basetop.o                                    \
+ pkgcmds.o      pkgdepcon.o    pkgdisplay.o   pkginfo.o      pkgkeys.o      \
+ pkglist.o      pkgsublist.o   pkgtop.o                                     \
+ methkeys.o     method.o       methparse.o    methlist.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+CPLUSPLUS = @CXX@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+OPTCFLAGS = @OPTCFLAGS@
+LDFLAGS = $(XLDFLAGS)
+
+EXTERNLIBS = -lncurses
+LIBS = -L../lib -ldpkg $(EXTERNLIBS) $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+ALL_CFLAGS_OPT = $(ALL_CFLAGS) $(OPTCFLAGS)
+
+.SUFFIXES:     .cc .o .c
+
+.cc.o:
+               $(CPLUSPLUS) $(ALL_CFLAGS) -c $<
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+all:           dselect
+
+dselect:       $(OBJ) ../lib/libdpkg.a
+               $(CC) $(LDFLAGS) -o dselect $(OBJ) $(LIBS)
+
+# These next few files are very heavily used, and should be optimised
+# for speed rather than space.  (ALL_CFLAGS_OPT usually means -O3.)
+pkgdepcon.o:   pkgdepcon.cc
+               $(CPLUSPLUS) $(ALL_CFLAGS_OPT) -c $<
+
+pkgdisplay.o:  pkgdisplay.cc
+               $(CPLUSPLUS) $(ALL_CFLAGS_OPT) -c $<
+
+curkeys.o:     curkeys.cc curkeys.inc
+               $(CPLUSPLUS) $(ALL_CFLAGS) -c curkeys.cc
+
+helpmsgs.h helpmsgs.cc:        helpmsgs.src mkhelpmsgs.pl
+               perl mkhelpmsgs.pl
+
+curkeys.inc:   keyoverride mkcurkeys.pl
+               perl mkcurkeys.pl keyoverride \
+                       `echo '#include <ncurses/curses.h>' | \
+                        $(CC) -E - | grep ncurses | head -1 | \
+                        sed -e 's/^[^"]*"//; s/".*$$//'` > curkeys.inc.new
+               mv curkeys.inc.new curkeys.inc
+
+kt:            kt.o
+               $(CC) $(LDFLAGS) -o kt kt.o $(LIBS)
+
+kt.o:          kt.c curkeys.inc
+
+clean:
+               rm -f curkeys.inc curkeys.inc.new
+               rm -f helpmsgs.h helpmsgs.cc helpmsgs.h.new helpmsgs.cc.new
+               rm -f *.o core dselect kt
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+               rm -rf t updates status available *.old
+
+install:       all
+               $(INSTALL_PROGRAM) -s dselect $(bindir)/dselect
+
+# $(INSTALL_DATA) dselect.8 $(man8dir)/dselect.$(man8)
+
+$(OBJ):                        dselect.h ../config.h ../include/dpkg.h ../include/dpkg-db.h
+main.o:                                                ../version.h ../include/myopt.h
+method.o:                                      method.h
+pkgcmds.o pkgdepcon.o pkgdisplay.o pkgtop.o:   pkglist.h
+baselist.o bindings.o curkeys.o main.o:                bindings.h method.h pkglist.h
+methlist.o methkeys.o pkginfo.o pkgkeys.o:     bindings.h method.h pkglist.h
+pkglist.o pkgsublist.o methparse.o:            bindings.h method.h pkglist.h
+helpmsgs.o methlist.o pkginfo.o basecmds.o:    helpmsgs.h helpmsgs.cc
diff --git a/dselect/basecmds.cc b/dselect/basecmds.cc
new file mode 100644 (file)
index 0000000..9181601
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bcommands.cc - base list keyboard commands display
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "helpmsgs.h"
+
+void baselist::kd_scrollon() {
+  topofscreen += list_height;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  if (cursorline < topofscreen)
+    setcursor(topofscreen);
+  refreshlist();
+}
+
+void baselist::kd_scrollon1() {
+  if (topofscreen >= nitems - list_height) return;
+  topofscreen++;
+  if (cursorline < topofscreen)
+    setcursor(topofscreen);
+  refreshlist();
+}
+
+void baselist::kd_scrollback() {
+  topofscreen -= list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  if (cursorline >= topofscreen + list_height)
+    setcursor(topofscreen + list_height - 1);
+  refreshlist();
+}
+
+void baselist::kd_scrollback1() {
+  if (topofscreen <= 0) return;
+  topofscreen--;
+  if (cursorline >= topofscreen + list_height)
+    setcursor(topofscreen + list_height - 1);
+  refreshlist();
+}
+
+void baselist::kd_top() {
+  topofscreen= 0; setcursor(0);
+}
+
+void baselist::kd_bottom() {
+  topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setcursor(lesserint(topofscreen + list_height - 1, nitems-1));
+}
+
+void baselist::kd_redraw() {
+//#define RFSH(x) werase(x); redrawwin(x)
+//  RFSH(listpad);
+//  RFSH(infopad); 
+//  RFSH(colheadspad); 
+//  RFSH(thisstatepad); 
+//  RFSH(titlewin); 
+//  RFSH(whatinfowin); /* fixme-ncurses: why does ncurses need this ? */
+  clearok(curscr,TRUE);
+  redrawall();
+  if (debug) fprintf(debug,"baselist[%p]::kd_redraw() done\n",this);
+}
+
+void baselist::kd_searchagain() {
+  if (!searchstring[0]) { beep(); return; }
+  dosearch();
+}
+
+void baselist::kd_search() {
+  werase(querywin);
+  mvwaddstr(querywin,0,0, "Search for ? ");
+  echo();
+  /* fixme: make / RET do `search again' and / DEL to abort */
+  if (wgetnstr(querywin,searchstring,sizeof(searchstring)-1) == ERR)
+    searchstring[0]= 0;
+  noecho();
+  if (whatinfo_height) { touchwin(whatinfowin); refreshinfo(); }
+  else if (info_height) { touchwin(infopad); refreshinfo(); }
+  else if (thisstate_height) redrawthisstate();
+  else { touchwin(listpad); refreshlist(); }
+  if (searchstring[0]) dosearch();
+}
+
+void baselist::displayhelp(const struct helpmenuentry *helpmenu, int key) {
+  const struct helpmenuentry *hme;
+  int maxx, maxy, i, y, x, nextkey;
+  
+  getmaxyx(stdscr,maxy,maxx);
+  clearok(stdscr,TRUE);
+  for (;;) {
+    werase(stdscr);
+    for (hme= helpmenu; hme->key && hme->key != key; hme++);
+    if (hme->key) {
+      attrset(list_attr);
+      mvaddstr(1,0, hme->msg->text);
+      attrset(title_attr);
+      mvaddstr(0,0, "Help: ");
+      addstr(hme->msg->title);
+      getyx(stdscr,y,x);
+      while (++x<maxx) addch(' ');
+      attrset(thisstate_attr);
+      mvaddstr(maxy-1,0,
+"? = help menu    Space = exit help    . = next help    or a help page key "
+               );
+      getyx(stdscr,y,x);
+      while (++x<maxx) addch(' ');
+      move(maxy,maxx);
+      attrset(A_NORMAL);
+      nextkey= hme[1].key;
+    } else {
+      mvaddstr(1,1, "Help information is available under the following topics:");
+      for (i=0, hme=helpmenu; hme->key; hme++,i++) {
+        attrset(A_BOLD);
+        mvaddch(i+3,3, hme->key);
+        attrset(A_NORMAL);
+        mvaddstr(i+3,6, hme->msg->title);
+      }
+      mvaddstr(i+4,1,
+               "Press a key from the list above, Space to exit help,\n"
+               "  or `.' (full stop) to read each help page in turn. ");
+      nextkey= helpmenu[0].key;
+    }
+    refresh();
+    key= getch();
+    if (key == EOF) ohshite("error reading keyboard in help");
+    if (key == ' ') {
+      break;
+    } else if (key == '?') {
+      key= 0;
+    } else if (key == '.') {
+      key= nextkey;
+    }
+  }
+  werase(stdscr);
+  clearok(stdscr,TRUE);
+  wnoutrefresh(stdscr);
+
+  redrawtitle();
+  refreshcolheads();
+  refreshlist();
+  redrawthisstate();
+  refreshinfo();
+  wnoutrefresh(whatinfowin);
+}     
+
+void baselist::kd_help() {
+  displayhelp(helpmenulist(),0);
+}
+
+void baselist::setcursor(int index) {
+  if (listpad && cursorline != -1) {
+    redrawitemsrange(cursorline,cursorline+1);
+    redraw1itemsel(cursorline,0);
+  }
+  if (cursorline != index) infotopofscreen= 0;
+  cursorline= index;
+  if (listpad) {
+    redrawitemsrange(cursorline,cursorline+1);
+    redraw1itemsel(cursorline,1);
+    refreshlist();
+    redrawthisstate();
+  }
+  redrawinfo();
+}
+
+void baselist::kd_down() {
+  int ncursor= cursorline;
+  // scroll by one line unless the bottom is already visible
+  // or we're in the top half of the screen ...
+  if (topofscreen < nitems - list_height &&
+      ncursor >= topofscreen + list_height - 3) topofscreen++;
+  // move cursor if there are any more ...
+  if (cursorline+1 < nitems) ncursor++;
+  setcursor(ncursor);
+}
+  
+void baselist::kd_up() {
+  int ncursor= cursorline;
+  // scroll by one line if there are any lines not shown yet
+  // and we're not in the bottom half the screen ...
+  if (topofscreen > 0 &&
+      ncursor <= topofscreen + 2) topofscreen--;
+  // move cursor if there are any to move it to ...
+  if (cursorline > 0) ncursor--;
+  setcursor(ncursor);
+}
+
+void baselist::kd_iscrollon() {
+  infotopofscreen += info_height;
+  if (infotopofscreen > infolines - info_height)
+    infotopofscreen= infolines - info_height;
+  if (infotopofscreen < 0) infotopofscreen= 0;
+  refreshinfo();
+}
+
+void baselist::kd_iscrollback() {
+  infotopofscreen -= info_height;
+  if (infotopofscreen < 0) infotopofscreen= 0;
+  refreshinfo();
+}
+
+void baselist::kd_iscrollon1() {
+  if (infotopofscreen >= infolines - info_height) return;
+  infotopofscreen++; refreshinfo();
+}
+
+void baselist::kd_iscrollback1() {
+  if (infotopofscreen <= 0) return;
+  infotopofscreen--; refreshinfo();
+}
+
+void baselist::kd_panon() {
+  leftofscreen += xmax/3;
+  if (leftofscreen > total_width - xmax) leftofscreen= total_width - xmax;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panback() {
+  leftofscreen -= xmax/3;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panon1() {
+  leftofscreen++;
+  if (leftofscreen > total_width - xmax) leftofscreen= total_width - xmax;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panback1() {
+  leftofscreen--;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
diff --git a/dselect/baselist.cc b/dselect/baselist.cc
new file mode 100644 (file)
index 0000000..5f7e892
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * baselist.cc - list of somethings
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+void mywerase(WINDOW *win) {
+  int my,mx,y,x;
+  getmaxyx(win,my,mx);
+  for (y=0; y<my; y++) {
+    wmove(win,y,0); for (x=0; x<mx; x++) waddch(win,' ');
+  }
+  wmove(win,0,0);
+}
+
+baselist *baselist::signallist= 0;
+void baselist::sigwinchhandler(int) {
+  baselist *p= signallist;
+  p->enddisplay();
+  endwin(); initscr();
+  p->startdisplay();
+  if (doupdate() == ERR) ohshite("doupdate in SIGWINCH handler failed");
+}
+
+static void cu_sigwinch(int, void **argv) {
+  struct sigaction *osigactp= (struct sigaction*)argv[0];
+  sigset_t *oblockedp= (sigset_t*)argv[1];
+  
+  if (sigaction(SIGWINCH,osigactp,0)) ohshite("failed to restore old SIGWINCH sigact");
+  delete osigactp;
+  if (sigprocmask(SIG_SETMASK,oblockedp,0)) ohshite("failed to restore old signal mask");
+  delete oblockedp;
+} 
+
+void baselist::setupsigwinch() {
+  sigemptyset(&sigwinchset);
+  sigaddset(&sigwinchset,SIGWINCH);
+    
+  osigactp= new(struct sigaction);
+  oblockedp= new(sigset_t);
+  if (sigprocmask(0,0,oblockedp)) ohshite("failed to get old signal mask");
+  if (sigaction(SIGWINCH,0,osigactp)) ohshite("failed to get old SIGWINCH sigact");
+
+  push_cleanup(cu_sigwinch,~0, 0,0, 2,(void*)osigactp,(void*)oblockedp);
+
+  if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to block SIGWINCH");
+  memset(&nsigact,0,sizeof(nsigact));
+  nsigact.sa_handler= sigwinchhandler;
+  sigemptyset(&nsigact.sa_mask);
+  nsigact.sa_flags= SA_INTERRUPT;
+  if (sigaction(SIGWINCH,&nsigact,0)) ohshite("failed to set new SIGWINCH sigact");
+}
+
+void baselist::startdisplay() {
+  if (debug) fprintf(debug,"baselist[%p]::startdisplay()\n",this);
+  cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
+  clear(); wnoutrefresh(stdscr);
+
+  // find attributes
+  if (has_colors() && start_color()==OK && COLOR_PAIRS >= 3) {
+    if (init_pair(1,COLOR_WHITE,COLOR_BLACK) != OK ||
+        init_pair(2,COLOR_WHITE,COLOR_RED) != OK ||
+        init_pair(3,COLOR_WHITE,COLOR_BLUE) != OK)
+      ohshite("failed to allocate colour pairs");
+    list_attr= COLOR_PAIR(1);
+    listsel_attr= list_attr|A_REVERSE;
+    title_attr= COLOR_PAIR(2);
+    thisstate_attr= COLOR_PAIR(3);
+    selstate_attr= list_attr|A_BOLD;
+    selstatesel_attr= listsel_attr|A_BOLD;
+  } else {
+    title_attr= A_REVERSE;
+    thisstate_attr= A_STANDOUT;
+    list_attr= 0;
+    listsel_attr= A_STANDOUT;
+    selstate_attr= A_BOLD;
+    selstatesel_attr= A_STANDOUT;
+  }
+  query_attr= title_attr;
+  info_attr= list_attr;
+  colheads_attr= info_headattr= A_BOLD;
+  whatinfo_attr= thisstate_attr;
+
+  // set up windows and pads, based on screen size
+  int y;  
+  getmaxyx(stdscr,ymax,xmax);
+  title_height= ymax>=6;
+  colheads_height= ymax>=5;
+  thisstate_height= ymax>=3;
+  whatinfo_height= ymax>=2;
+  y= ymax - (title_height + colheads_height +
+               thisstate_height + whatinfo_height);
+  assert(y>=1);
+  y-= list_height + info_height;
+  if (y>0) {
+    list_height += (y+1)/2;
+    info_height += y/2;
+  } else if (y<0) {
+    list_height -= (-y)/2;
+    info_height -= (-y+1)/2;
+  }
+  colheads_row= title_height;
+  list_row= colheads_row + colheads_height;
+  thisstate_row= list_row + list_height;
+  info_row= thisstate_row + thisstate_height;
+  whatinfo_row= info_row + info_height;
+
+  setwidths();
+  
+  titlewin= newwin(1,xmax, 0,0);
+  if (!titlewin) ohshite("failed to create title window");
+  wattrset(titlewin,title_attr);
+  
+  whatinfowin= newwin(1,xmax, whatinfo_row,0);
+  if (!whatinfowin) ohshite("failed to create whatinfo window");
+  wattrset(whatinfowin,whatinfo_attr);
+  
+  listpad= newpad(nitems+1, total_width);
+  if (!listpad) ohshite("failed to create baselist pad");
+  
+  colheadspad= newpad(1, total_width);
+  if (!colheadspad) ohshite("failed to create heading pad");
+  wattrset(colheadspad,colheads_attr);
+  
+  thisstatepad= newpad(1, total_width);
+  if (!thisstatepad) ohshite("failed to create thisstate pad");
+  wattrset(thisstatepad,thisstate_attr);
+
+  infopad= newpad(MAX_DISPLAY_INFO, total_width);
+  if (!infopad) ohshite("failed to create info pad");
+  wattrset(infopad,info_attr);
+
+  querywin= newwin(1,xmax,ymax-1,0);
+  if (!querywin) ohshite("failed to create query window");
+
+  if (cursorline >= topofscreen + list_height) topofscreen= cursorline;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+
+  infotopofscreen= 0; leftofscreen= 0;
+
+  redrawall();
+
+  if (debug)
+    fprintf(debug,
+            "baselist::startdisplay() done ...\n\n"
+            " xmax=%d, ymax=%d;\n\n"
+            " title_height=%d, colheads_height=%d, list_height=%d;\n"
+            " thisstate_height=%d, info_height=%d, whatinfo_height=%d;\n\n"
+            " colheads_row=%d, thisstate_row=%d, info_row=%d;\n"
+            " whatinfo_row=%d, list_row=%d;\n\n",
+            xmax, ymax,
+            title_height, colheads_height, list_height,
+            thisstate_height, info_height, whatinfo_height,
+            colheads_row, thisstate_row, info_row,
+            whatinfo_row, list_row);
+
+}
+
+void baselist::enddisplay() {
+  delwin(titlewin);
+  delwin(whatinfowin);
+  delwin(listpad);  
+  delwin(colheadspad);  
+  delwin(thisstatepad);
+  delwin(infopad);
+  wmove(stdscr,ymax,0); wclrtoeol(stdscr);
+  listpad= 0;
+}
+
+void baselist::redrawall() {
+  redrawtitle();
+  redrawcolheads();
+  wattrset(listpad,list_attr); mywerase(listpad);
+  ldrawnstart= ldrawnend= -1; // start is first drawn; end is first undrawn; -1=none
+  refreshlist();
+  redrawthisstate();
+  redrawinfo();
+}
+
+void baselist::redraw1item(int index) {
+  redraw1itemsel(index, index == cursorline);
+}
+
+baselist::baselist(keybindings *kb) {
+  if (debug)
+    fprintf(debug,"baselist[%p]::baselist()\n",this);
+
+  bindings= kb;
+  nitems= 0;
+
+  xmax= -1;
+  list_height=0; info_height=0;
+  topofscreen= 0; leftofscreen= 0;
+  listpad= 0; cursorline= -1;
+
+  searchstring[0]= 0;
+}  
+
+void baselist::itd_keys() {
+  whatinfovb("keybindings");
+  
+  const int givek= xmax/3;
+  bindings->describestart();
+  const char **ta;
+  while ((ta= bindings->describenext()) != 0) {
+    const char **tap= ta+1;
+    for (;;) {
+      waddstr(infopad, *tap);
+      tap++;  if (!*tap) break;
+      waddstr(infopad, ", ");
+    }
+    int y,x;
+    getyx(infopad,y,x);
+    if (x >= givek) y++;
+    mvwaddstr(infopad, y,givek, ta[0]);
+    waddch(infopad,'\n');
+  }
+}
+
+void baselist::dosearch() {
+  int offset, index, searchlen;
+  searchlen= strlen(searchstring);
+  if (debug) fprintf(debug,"packagelist[%p]::dosearch(); searchstring=`%s' len=%d\n",
+                     this,searchstring,searchlen);
+  for (offset=1, index=greaterint(topofscreen,cursorline+1);
+       offset<nitems;
+       offset++, index++) {
+    if (index >= nitems) index -= nitems;
+    int lendiff, i;
+    const char *thisname;
+    thisname= itemname(index);
+    if (!thisname) continue;
+    lendiff= strlen(thisname) - searchlen;
+    for (i=0; i<=lendiff; i++)
+      if (!strncasecmp(thisname + i, searchstring, searchlen)) {
+        topofscreen= index-1;
+        if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
+        if (topofscreen < 0) topofscreen= 0;
+        setcursor(index);
+        return;
+      }
+  }
+  beep();
+}
+
+void baselist::refreshinfo() {
+  pnoutrefresh(infopad, infotopofscreen,leftofscreen, info_row,0,
+               lesserint(info_row + info_height - 1, info_row + MAX_DISPLAY_INFO - 1),
+               lesserint(total_width - leftofscreen - 1, xmax - 1));
+  
+  if (whatinfo_height) {
+    mywerase(whatinfowin);
+    mvwaddstr(whatinfowin,0,0, whatinfovb.string());
+    if (infolines > info_height) {
+      wprintw(whatinfowin,"  -- %d%%, press ",
+              (int)((infotopofscreen + info_height) * 100.0 / infolines));
+      if (infotopofscreen + info_height < infolines) {
+        wprintw(whatinfowin,"%s for more", bindings->find("iscrollon"));
+        if (infotopofscreen) waddstr(whatinfowin, ", ");
+      }
+      if (infotopofscreen)
+        wprintw(whatinfowin, "%s to go back",bindings->find("iscrollback"));
+      waddch(whatinfowin,'.');
+    }
+    wnoutrefresh(whatinfowin);
+  }
+}
+
+void baselist::wordwrapinfo(int offset, const char *m) {
+  int usemax= xmax-5;
+  if (debug) fprintf(debug,"baselist[%p]::wordwrapinfo(%d, `%s')\n",this,offset,m);
+  int wrapping=0;
+  for (;;) {
+    int offleft=offset; while (*m == ' ' && offleft>0) { m++; offleft--; }
+    const char *p= strchr(m,'\n');
+    int l= p ? (int)(p-m) : strlen(m);
+    while (l && isspace(m[l-1])) l--;
+    if (!l || *m == '.' && l == 1) {
+      if (wrapping) waddch(infopad,'\n');
+      waddch(infopad,'\n');
+      wrapping= 0;
+    } else if (*m == ' ' || usemax < 10) {
+      if (wrapping) waddch(infopad,'\n');
+      waddnstr(infopad, m, l);
+      waddch(infopad,'\n'); wrapping= 0;
+    } else {
+      int x,y;
+      if (wrapping) {
+        getyx(infopad, y,x);
+        if (x+1 >= usemax) {
+          waddch(infopad,'\n');
+        } else {
+          waddch(infopad,' ');
+        }
+      }
+      for (;;) {
+        getyx(infopad, y,x);
+        int dosend= usemax-x;
+        if (l <= dosend) {
+          dosend=l;
+        } else {
+          int i=dosend;
+          while (i > 0 && m[i] != ' ') i--;
+          if (i > 0 || x > 0) dosend=i;
+        }
+        if (dosend) waddnstr(infopad, m, dosend);
+        while (dosend < l && m[dosend] == ' ') dosend++;
+        l-= dosend; m+= dosend;
+        if (l <= 0) break;
+        waddch(infopad,'\n');
+      }
+      wrapping= 1;
+    }
+    if (!p) break;
+    m= ++p;
+  }
+  if (debug) fprintf(debug,"baselist[%p]::wordwrapinfo() done\n",this);
+}
+
+baselist::~baselist() { }
diff --git a/dselect/basetop.cc b/dselect/basetop.cc
new file mode 100644 (file)
index 0000000..54b7927
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bdrawtop.cc - base list class redraw of top
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+
+void baselist::refreshlist() {
+  redrawitemsrange(topofscreen,lesserint(nitems,topofscreen+list_height));
+  int y, x, maxy, maxx;
+  y= lesserint(list_row + list_height - 1,
+               list_row + nitems - topofscreen - 1);
+  x= lesserint(total_width - leftofscreen - 1,
+               xmax - 1);
+  pnoutrefresh(listpad, topofscreen,leftofscreen, list_row,0, y,x);
+  getmaxyx(listpad,maxy,maxx);
+  y++;
+  while (y < list_row + list_height - 1) {
+    pnoutrefresh(listpad, maxy-1,leftofscreen, y,0, y,x);
+    y++;
+  }
+}
+
+void baselist::redrawitemsrange(int start, int end) {
+  if (ldrawnstart==-1) { ldrawnstart= ldrawnend= end; }
+  while (ldrawnstart > start) { ldrawnstart--; redraw1item(ldrawnstart); }
+  while (ldrawnend < end) { redraw1item(ldrawnend); ldrawnend++; }
+}
+
+void baselist::refreshcolheads() {
+  pnoutrefresh(colheadspad, 0,leftofscreen, colheads_row,0,
+               colheads_row, lesserint(total_width - leftofscreen - 1, xmax - 1));
+}
diff --git a/dselect/bindings.cc b/dselect/bindings.cc
new file mode 100644 (file)
index 0000000..4aa3835
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bindings.cc - keybinding manager object definitions and default bindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+keybindings::keybindings(const interpretation *ints, const orgbinding *orgbindings) {
+  interps= ints;
+  bindings=0;
+  const orgbinding *b= orgbindings;
+  while (b->action) { bind(b->key,b->action); b++; }
+  describestart();
+}
+
+int keybindings::bind(int key, const char *action) {
+  if (key == -1) return 0;
+  
+  const interpretation *interp;
+  for (interp=interps; interp->action && strcmp(interp->action,action); interp++);
+  if (!interp->action) return 0;
+  
+  const description *desc;
+  for (desc=descriptions; desc->action && strcmp(desc->action,action); desc++);
+
+  binding *bind;
+  for (bind=bindings; bind && bind->key != key; bind=bind->next);
+  
+  if (!bind) {
+    bind= new binding;
+    bind->key= key;
+    bind->next= bindings;
+    bindings= bind;
+  }
+  bind->interp= interp;
+  bind->desc= desc ? desc->desc : 0;
+  return 1;
+}
+
+const char *keybindings::find(const char *action) {
+  binding *b;
+  for (b=bindings; b && strcmp(action,b->interp->action); b=b->next);
+  if (!b) return "[not bound]";
+  const char *n= key2name(b->key);
+  if (n) return n;
+  static char buf[50];
+  sprintf(buf,"[unk: %d]",b->key);
+  return buf;
+}
+
+const keybindings::interpretation *keybindings::operator()(int key) {
+  binding *b;
+  for (b=bindings; b && b->key != key; b=b->next);
+  if (!b) return 0;
+  return b->interp;
+}
+
+const char **keybindings::describenext() {
+  binding *search;
+  int count;
+  for (;;) {
+    if (!iterate->action) return 0;
+    for (count=0, search=bindings; search; search=search->next)
+      if (!strcmp(search->interp->action,iterate->action))
+        count++;
+    if (count) break;
+    iterate++;
+  }
+  const char **retarray= new const char *[count+2];
+  retarray[0]= iterate->desc;
+  for (count=1, search=bindings; search; search=search->next)
+    if (!strcmp(search->interp->action,iterate->action))
+      retarray[count++]= key2name(search->key);
+  retarray[count]= 0;
+  iterate++;
+  return retarray;
+}
+
+const char *keybindings::key2name(int key) {
+  const keyname *search;
+  for (search=keynames; search->key != -1 && search->key != key; search++);
+  return search->kname;
+}
+
+int keybindings::name2key(const char *name) {
+  const keyname *search;
+  for (search=keynames; search->kname && strcasecmp(search->kname,name); search++);
+  return search->key;
+}
+
+keybindings::~keybindings() {
+  binding *search, *next;
+  for (search=bindings; search; search=next) {
+    next= search->next;
+    delete search;
+  }
+}
+
+const keybindings::description keybindings::descriptions[]= {
+  // Actions which apply to both types of list.
+  { "iscrollon",       "Scroll onwards through help/information"               },
+  { "iscrollback",     "Scroll backwards through help/information"             },
+  { "up",              "Move up"                                               },
+  { "down",            "Move down"                                             },
+  { "top",             "Go to top of list"                                     },
+  { "bottom",          "Go to end of list"                                     },
+  { "help",            "Request help (cycle through help screens)"             },
+  { "info",            "Cycle through information displays"                    },
+  { "redraw",          "Redraw display"                                        },
+  { "scrollon1",       "Scroll onwards through list by 1 line"                 },
+  { "scrollback1",     "Scroll backwards through list by 1 line"               },
+  { "iscrollon1",      "Scroll onwards through help/information by 1 line"     },
+  { "iscrollback1",    "Scroll backwards through help/information by 1 line"   },
+  { "scrollon",        "Scroll onwards through list"                           },
+  { "scrollback",      "Scroll backwards through list"                         },
+
+  // Actions which apply only to lists of packages.
+  { "select",          "Select package(s) for installation"                    },
+  { "deselect",        "Mark package(s) for deinstallation"                    },
+  { "purge",           "Mark package(s) for deinstall and purge"               },
+  { "morespecific",    "Make highlight more specific"                          },
+  { "lessspecific",    "Make highlight less specific"                          },
+  { "search",          "Search for a package whose name contains a string"     },
+  { "searchagain",     "Repeat last search."                                   },
+  { "swaporder",       "Swap sort order priority/section"                      },
+  { "quitcheck",       "Quit, confirming, and checking dependencies"           },
+  { "quitnocheck",     "Quit, confirming without check"                        },
+  { "quitrejectsug",   "Quit, rejecting conflict/dependency suggestions"       },
+  { "abortnocheck",    "Abort - quit without making changes"                   },
+  { "revert",          "Revert to old state for all packages"                  },
+  { "revertsuggest",   "Revert to suggested state for all packages"            },
+  { "revertdirect",    "Revert to directly requested state for all packages"   },
+  
+  // Actions which apply only to lists of methods.
+  { "select-and-quit", "Select currently-highlighted access method"            },
+  { "abort",           "Quit without changing selected access method"          },
+  {  0,                0                                                       }
+};
diff --git a/dselect/bindings.h b/dselect/bindings.h
new file mode 100644 (file)
index 0000000..981cf63
--- /dev/null
@@ -0,0 +1,94 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * bindings.h - keybindings class header file
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef BINDINGS_H
+#define BINDINGS_H
+
+enum quitaction;
+
+struct keybindings {
+  struct interpretation;
+
+  struct orgbinding {
+    int key;
+    const char *action;
+  };
+  
+  struct keyname {
+    int key;
+    const char *kname;
+  };
+  
+  struct description {
+    const char *action, *desc;
+  };
+
+  struct binding {
+    binding *next;
+    int key;
+    const struct interpretation *interp;
+    const char *desc;
+  };
+  
+ private:
+  static const keyname keynames[];
+  static const description descriptions[];
+
+  binding *bindings;
+  const description *iterate;
+  const interpretation *interps;
+  
+  int bind(int key, const char *action);
+  
+ public:
+  int name2key(const char *name);
+  const char *key2name(int key);
+  
+  int bind(const char *name, const char *action) { return bind(name2key(name),action); }
+  const interpretation *operator()(int key);
+  const char *find(const char *action);
+
+  void describestart() { iterate=descriptions; }
+  const char **describenext();
+  //... returns array, null-term, first element is description, rest are key strings
+  // caller must delete[] the array.  Null means end.
+
+  keybindings(const interpretation *ints, const orgbinding *orgbindings);
+  ~keybindings();
+};
+
+#include "pkglist.h"
+#include "method.h"
+
+struct keybindings::interpretation {
+  const char *action;
+  void (methodlist::*mfn)();
+  void (packagelist::*pfn)();
+  quitaction qa;
+};
+
+extern const keybindings::interpretation packagelist_kinterps[];
+extern const keybindings::orgbinding packagelist_korgbindings[];
+
+extern const keybindings::interpretation methodlist_kinterps[];
+extern const keybindings::orgbinding methodlist_korgbindings[];
+
+#endif /* BINDINGS_H */
diff --git a/dselect/checkunimp.pl b/dselect/checkunimp.pl
new file mode 100755 (executable)
index 0000000..c0b723b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+while(<>) {
+    if (m/^\s+\{\s+\"(\w[^"]+)\",\s+0,\s+\w+list\:\:kd_\w+,\s+qa_\w+\s+\},\s*$/ ||
+        m/^\s+\{\s+\"(\w[^"]+)\",\s+\w+list\:\:kd_\w+,\s+0,\s+qa_\w+\s+\},\s*$/) {
+        $implem{$1}= 1;
+    } elsif (m/^\s+\{\s+(\S.{0,15}\S),\s+\"(\w[^"]+)\"\s+\},\s*$/) {
+        $bound{$2} .= $1.', ';
+    } elsif (m/^\s+\{\s+0,/ || m/^\s+\{\s+-1,/) {
+    } elsif (m/^\s+\{\s+/) {
+        print "huh ? $_";
+    }
+}
+for $f (sort keys %bound) {
+    next if defined($implem{$f});
+    $b=$bound{$f}; $b =~ s/, $//;
+    printf "unimplemented: %-20s (%s)\n", $f, $b;
+}
diff --git a/dselect/curkeys.cc b/dselect/curkeys.cc
new file mode 100644 (file)
index 0000000..532b269
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * curkeys.cc - list of ncurses keys for name <-> key mapping
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+extern "C" {
+#include <ncurses/curses.h>
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::keyname keybindings::keynames[] = {
+#include "curkeys.inc"
+};
diff --git a/dselect/debugmake b/dselect/debugmake
new file mode 100755 (executable)
index 0000000..0270297
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -O0' LDFLAGS=-g 'EXTERNLIBS= -lncurses_g -lefence' "$@"
diff --git a/dselect/dselect.8 b/dselect/dselect.8
new file mode 100644 (file)
index 0000000..8e7e6d5
--- /dev/null
@@ -0,0 +1,89 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH DSELECT 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+dselect \- a user tool to manage Debian GNU/Linux packages
+
+.SH SYNOPSIS
+.B dselect
+[options]
+.br
+.B dselect
+[options] action ...
+
+.SH DESCRIPTION
+.B dselect
+is the primary user interface for installing, removing and managing
+Debian GNU/Linux packages. It is an front-end to
+.B dpkg(8).
+Normally
+.B dselect
+is invoked without parameters, but some commandline parameters are still
+available.
+
+The usage of
+.B dselect
+is pretty self-explanatory, and also an internal help-system is
+included, which describes the keystrokes and some general concepts.
+.I Read the help.
+
+.SS ACTIONS
+.TP
+.B access, update, select, install, config, remove
+These actions automatically selects corresponding commands from the main
+menu, without even showing the main menu to you.
+.TP
+.B quit
+Do nothing but quit.
+.TP
+.B menu
+Displays the default menu. This is equivalent to starting
+.B dselect
+with no parameters.
+
+.SS OPTIONS
+.TP
+.B --admindir <directory>
+Changes the directory where datafiles are located. This defaults to
+.I /var/lib/dpkg.
+Note, that these files are just some internal datafiles, actual Debian
+packages doesn't have to be located here.
+.TP
+.B --debug <file> | -D<file>
+Turn on debugging. Debugging information is sent to
+.I <file>.
+.TP
+.B --help
+Print a brief help text.
+.TP
+.B --licence
+Print the licence of
+.B dselect.
+.TP
+.B --version
+Print version information.
+
+.SH BUGS
+This manpage doesn't document the options quite correctly, and has
+formatting inconsistent with other manpages.
+
+The
+.B dselect
+package selection interface is confusing or even alarming to the new
+user.
+
+There is no easy way automatically to download and install packages
+via anonymous FTP.
+
+.SH SEE ALSO
+.B deb(5)
+,
+.B dpkg-deb(8)
+,
+.B dpkg(8)
+and
+.B deb-control(5)
+
+.SH AUTHOR
+.B dselect
+was written by Ian Jackson (ijackson@gnu.ai.mit.edu).
+This manual page is by Juho Vuori (javuori@cc.helsinki.fi).
diff --git a/dselect/dselect.h b/dselect/dselect.h
new file mode 100644 (file)
index 0000000..5f35750
--- /dev/null
@@ -0,0 +1,149 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * dselect.h - external definitions for this program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DSELECT_H
+#define DSELECT_H
+
+#define TOTAL_LIST_WIDTH 180
+#define MAX_DISPLAY_INFO 120
+
+struct helpmenuentry {
+  char key;
+  const struct helpmessage *msg;
+};
+
+class keybindings;
+
+class baselist {
+protected:
+  // Screen dimensions &c.
+  int xmax, ymax;
+  int title_height, colheads_height, list_height;
+  int thisstate_height, info_height, whatinfo_height;
+  int colheads_row, thisstate_row, info_row, whatinfo_row, list_row;
+  int list_attr, listsel_attr, title_attr, colheads_attr, info_attr;
+  int info_headattr, whatinfo_attr;
+  int thisstate_attr, query_attr;
+  int selstate_attr, selstatesel_attr;
+  
+  int total_width;
+  
+  // (n)curses stuff
+  WINDOW *listpad, *infopad, *colheadspad, *thisstatepad;
+  WINDOW *titlewin, *whatinfowin, *querywin;
+  // If listpad is null, then we have not started to display yet, and
+  // so none of the auto-displaying update routines need to display.
+
+  // SIGWINCH handling
+  struct sigaction *osigactp, nsigact;
+  sigset_t *oblockedp, sigwinchset;
+  void setupsigwinch();
+
+  static baselist *signallist;
+  static void sigwinchhandler(int);
+
+  int nitems, ldrawnstart, ldrawnend;
+  int topofscreen, leftofscreen, cursorline;
+  int infotopofscreen, infolines;
+  varbuf whatinfovb;
+  char searchstring[50];
+
+  void unsizes();
+  void dosearch();
+  void displayhelp(const struct helpmenuentry *menu, int key);
+
+  void redrawall();
+  void redrawitemsrange(int start /*inclusive*/, int end /*exclusive*/);
+  void redraw1item(int index);
+  void refreshlist();
+  void refreshinfo();
+  void refreshcolheads();
+  void setcursor(int index);
+
+  void itd_keys();
+
+  virtual void redraw1itemsel(int index, int selected) =0;
+  virtual void redrawcolheads() =0;
+  virtual void redrawthisstate() =0;
+  virtual void redrawinfo() =0;
+  virtual void redrawtitle() =0;
+  virtual void setwidths() =0;
+  virtual const char *itemname(int index) =0;
+  virtual const struct helpmenuentry *helpmenulist() =0;
+
+  void wordwrapinfo(int offset, const char *string);
+  
+public:
+
+  keybindings *bindings;
+
+  void kd_up();
+  void kd_down();
+  void kd_redraw();
+  void kd_scrollon();
+  void kd_scrollback();
+  void kd_scrollon1();
+  void kd_scrollback1();
+  void kd_panon();
+  void kd_panback();
+  void kd_panon1();
+  void kd_panback1();
+  void kd_top();
+  void kd_bottom();
+  void kd_iscrollon();
+  void kd_iscrollback();
+  void kd_iscrollon1();
+  void kd_iscrollback1();
+  void kd_search();
+  void kd_searchagain();
+  void kd_help();
+
+  void startdisplay();
+  void enddisplay();
+
+  baselist(keybindings*);
+  virtual ~baselist();
+};
+
+static inline int lesserint(int a, int b) { return a<b ? a : b; }
+static inline int greaterint(int a, int b) { return a>b ? a : b; }
+
+void displayhelp(const struct helpmenuentry *menu, int key);
+
+void mywerase(WINDOW *win);
+
+void curseson();
+void cursesoff();
+
+extern const char *admindir;
+extern FILE *debug;
+
+enum urqresult { urqr_normal, urqr_fail, urqr_quitmenu };
+enum quitaction { qa_noquit, qa_quitchecksave, qa_quitnochecksave };
+
+typedef urqresult urqfunction(void);
+urqfunction urq_list, urq_quit, urq_menu;
+urqfunction urq_setup, urq_update, urq_install, urq_config, urq_remove;
+
+urqresult falliblesubprocess(const char *exepath, const char *name,
+                             const char *const *args);
+
+#endif /* DSELECT_H */
diff --git a/dselect/helpmsgs.src b/dselect/helpmsgs.src
new file mode 100644 (file)
index 0000000..db0fd6a
--- /dev/null
@@ -0,0 +1,179 @@
+@@@ listkeys Keystrokes
+
+Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:
+  n, Down-arrow         p, Up-arrow             move highlight
+  N, Page-down, Space   P, Page-up, Backspace   scroll list by 1 page
+  ^n                    ^p                      scroll list by 1 line
+  t, Home               e, End                  jump to top/end of list
+  u                     d                       scroll info by 1 page
+  ^u                    ^d                      scroll info by 1 line
+  B, Left-arrow         F, Right-arrow          pan display by 1/3 screen
+  ^b                    ^f                      pan display by 1 character
+
+Package states - selection:                    Package states - hold flag:
+  +, Insert   select package(s)                  H  put package(s) `on hold'
+  -, Delete   deselect package(s)                G  `go' - take off hold
+  _           deselect, purge configuration
+                                             Miscellaneous:
+Quit, exit, overwrite (note capitals!):         ? request help (also Help, F1)
+ Return  Confirm and quit (check dependencies)  i toggle/cycle info displays      
+   Q     Confirm and quit (override dep.s)      o cycle through sort orders       
+   X     eXit, abandoning any changes made      v toggle verbose status display   
+   R     Revert to state before this list      ^l redraw display                  
+   U     set all to sUggested state             / search (hit Return to cancel)
+   D     set all to Directly selected state     \\ repeat last search             
+
+@@@ mainintro Introduction to package list
+
+Welcome to the main package listing.  Please read the help that is available !
+
+You will be presented with a list of packages which are installed or available
+for installation.  You can navigate around the list using the cursor keys,
+selecting packages for installation (using `+') or deinstallation (using `-').
+
+Packages can be selected either singly or in groups; initially you will see
+that the line `All packages' is highlighted.  (De)selecting will affect all the
+packages described by the highlighted line.  Use `o' to change the order of the
+list (this also changes which kinds of group selections are possible).
+
+(Mainly for new installations:) Standard packages will be selected by default.
+Use capital `D' or `R' key to override this - see the keybindings help screen.
+
+Some of your choices will cause conflicts or dependency problems; you will be
+given a sub-list of the relevant packages, so that you can solve the problems.
+
+When you are satisfied with your choices you should press Return to confirm
+your changes and leave the package listing.  A final check on conflicts and
+dependencies will be done - here too you may see a sublist.
+
+Press Space to leave help and enter the list; press `?' at any time for help.
+
+@@@ readonlyintro Introduction to package list browser (read-only)
+
+Welcome to dselect's main package listing.  Since you do not have the
+privilege necessary to update package selections you are in read-only mode.
+
+Much on-line help is available, please make use of it !  Press `?' for help.
+You should read the list of keys and the explanations of the display.
+
+You will be presented with a list of packages which are installed or available
+for installation.  You can navigate around the list using the cursor keys (just
+as you would be able to do if you had read/write access - see the keystrokes
+help screen) and observe the status of the packages and read information about
+them.
+
+Press Space to leave help and enter the list; press `?' at any time for help.
+When you have finished browsing, press `q' or Return to quit.
+
+@@@ recurintro Introduction to conflict/dependency resolution sub-list
+
+Dependency/conflict resolution - introduction.
+
+One or more of your choices have raised a conflict or dependency problem -
+some packages should only be installed in conjunction with certain others, and
+some combinations of packages may not be installed together.
+
+You will see a sub-list containing the packages involved.  The bottom half of
+the display shows relevant conflicts and dependencies; use `i' to cycle between
+that, the package descriptions and the internal control information.
+
+A set of `suggested' selections has been calculated, and the initial selections
+in this sub-list have been set to match those, so you can just hit Return to
+accept the suggestions if you wish.  You may abort the change(s) which caused
+the problem(s), and go back to the main list, by pressing capital `X'.
+
+You can also move around the list and change the selections so that they are
+more like what you want, and you can `reject' my suggestions by using the
+capital `D' or `R' keys (see the keybindings help screen).  You can use capital
+`Q' to force me to accept the current selections, in case you want to override
+a recommendation or think that the program is mistaken.
+
+Press Space to leave help and enter the sub-list; remember: press `?' for help.
+
+@@@ displayexplain1 Display, part 1: package listing and status chars
+
+The top half of the screen shows a list of packages.  For each package you see
+four columns for its current status and selected-ness.  In terse mode (use `v'
+to toggle verbose display) these are single characters, from left to right:
+
+ Hold/error flag: h - you have put the package on Hold - it won't be processed
+                  R - serious error during installation, needs reinstallation;
+                  X - serious error, needs reinstallation, package also on hold
+ Installed state: Space - not installed;
+                   `*'  - installed;
+                   `-'  - not installed but config files remain;
+                   `u'  - unpacked but not yet configured;
+                   `C'  - half-configured (an error happened);
+                   `I'  - half-installed (an error happened).
+ Old selection: whether this package was selected before presenting this list;
+ Selection: whether this package is selected for installation:
+  `*': selected for installation;
+  `-': deselected (selected for removal, but configuration files will remain);
+  `_': deselected (purge completely, even remove configuration);
+  `n': package is new to this system (appears under `Old selection').
+
+Following those four columns are the Priority and Section of the package,
+its name (possibly truncated to fit) and the summary description.
+
+@@@ displayexplain2 Display, part 2: list highlight; information display
+
+* Highlight: One line in the package list will be highlighted.  It indicates
+  which package(s) will be selected/deselected by presses of `+', '-' and `_'.
+
+* The dividing line in the middle of the screen shows a brief explanation of
+  the status of the currently-highlighted package, or a description of which
+  group is highlighted if a group line is.  If you don't understand the
+  meaning of some of the status characters displayed, go to the relevant
+  package and look at this divider line, or use the `v' key for a verbose
+  display (press `v' again to go back to the terse display).
+
+* The bottom of the screen shows more information about the
+  currently-highlighted package (if there is only one).
+
+  It can show an extended description of the package, the internal package
+  control details, or information about conflicts and dependencies involving
+  the current package (in conflict/dependency resolution sublists).
+
+  Use the `i' key to cycle through the displays.
+
+@@@ methintro Introduction to method selection display
+
+dselect and dpkg can do automatic installation, loading the package files to be
+installed from one of a number of different possible places.
+
+This list allows you to select one of these installation methods.
+
+Move the highlight to the method you wish to use, and hit Enter.  You will then
+be prompted for the information required to do the installation.
+
+As you move the highlight a description of each method, where available, is
+displayed in the bottom half of the screen.
+
+If you wish to quit without changing anything use the `x' key while in the list
+of installation methods.
+
+A full list of keystrokes is available by pressing `k' now, or from the help
+menu reachable by pressing `?'.
+
+@@@ methkeys Keystrokes for method selection
+
+Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:
+  n, Down-arrow         p, Up-arrow             move highlight
+  N, Page-down, Space   P, Page-up, Backspace   scroll list by 1 page
+  ^n                    ^p                      scroll list by 1 line
+  t, Home               e, End                  jump to top/end of list
+  u                     d                       scroll info by 1 page
+  ^u                    ^d                      scroll info by 1 line
+  B, Left-arrow         F, Right-arrow          pan display by 1/3 screen
+  ^b                    ^f                      pan display by 1 character
+(These are the same motion keys as in the package list display.)
+
+Quit:
+ Return, Enter    select this method and go to its configuration dialogue
+ x, X             exit without changing or setting up the installation method
+
+Miscellaneous:
+  ?, Help, F1      request help
+ ^l                redraw display                  
+  /                search (just return to cancel)  
+  \\                repeat last search             
diff --git a/dselect/junk b/dselect/junk
new file mode 100644 (file)
index 0000000..e2ae289
--- /dev/null
@@ -0,0 +1,162 @@
+const packagelist::infotype packagelist::helpinfos[]= {
+  { itr_nonrecursive,  itd_mainwelcome      },
+  { itr_recursive,     itd_recurwelcome     },
+  { 0,                 itd_keys             },
+  { 0,                 itd_explaindisplay   },
+  { 0,                 0                    }
+};
+
+int packagelist::itr_nonrecursive() { return !recursive; }
+
+void packagelist::itd_mainwelcome() {
+  whatinfovb("main welcome page");
+
+  varbuf vb;
+  vb("This is dselect's main package listing screen.");
+  if (!readwrite) vb("  (read-only access.)");
+  vb("\n\n"
+     "Please press `");
+  vb(bindings->find("help"));
+  vb("' repeatedly to show more help, including the list of "
+     "keystrokes and an explanation of the display; use `");
+  vb(bindings->find("iscrollon"));
+  vb("' and `");
+  vb(bindings->find("iscrollback"));
+  vb("' to scroll this help screen.  Press `");
+  vb(bindings->find("info"));
+  vb("' repeatedly to see more information about the highlighted package(s).\n"
+     "\n");
+  if (readwrite) {
+    vb("Move the highlight and use `");
+    vb(bindings->find("select"));
+    vb("' and `");
+    vb(bindings->find("deselect"));
+    vb("' to select and deselect packages for "
+       "installation.  Press `");
+    vb(bindings->find("quit"));
+    vb("' to confirm your changes and quit, or `");
+    vb(bindings->find("abortnocheck"));
+    vb("' to abort without making changes.\n"
+       "\n"
+       "Deselecting a package that is currently "
+       "installed will arrange for it to be deinstalled later.  If you "
+       "select a package for purging its configuration files will be "
+       "deleted when the package is; usually they are kept.\n");
+  } else {
+    vb("You do not have read/write access to the package administration "
+       "area, so you may only examine the state of packages.\n");
+  }
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_explaindisplay() {
+  whatinfovb("explanation of the display");
+
+  varbuf vb;
+  vb("The top half of the screen shows a list of packages.  For each "
+     "package its status (explained in more detail below), class, "
+     "section, name and a summary of its description is shown.\n"
+     "\n"
+     "In the middle of the screen is a status line containing a description "
+     "of the status of the currently highlighted package (or a description "
+     "of which packages are highlighted if this is more than one package).\n"
+     "\n"
+     "The bottom half of the screen is used to display more extended "
+     "information about the highlighed package(s), and for help displays "
+     "like this one.\n"
+     "\n"
+     "The four characters at the start of each package's entry in the list "
+     "show its status: Error, Installed, Old, Wanted.\n"
+     "\n"
+     "`Wanted' is whether it is currently "
+     "selected or not (ie, its desired state as currently being edited); "
+     "`Old', immediately to the left of that, gives the desired state before "
+     "this package list was entered, if different (or a space if not)."
+     "\n"
+     "`Installed' shows the package's current actual state on "
+     "the system; the `Error' column is used to mark packages for which "
+     "installation or removal errors have occurred.\n");
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_recurwelcome() {
+  whatinfovb("recursive package listing welcome page");
+  
+  varbuf vb;
+  vb("Some of the packages you have selected require or recommend "
+     "the installation of other packages you haven't selected, or "
+     "some of them conflict with packages you have selected.\n"
+     "Details of problems for each package are available by pressing `");
+  vb(bindings->find("info"));
+  vb("'.\n"
+     "This sub-list of packages is to allow you to resolve these "
+     "dependencies and conflicts.  You may accept my suggestions "
+     "about which related packages to select or deselect by pressing `");
+  vb(bindings->find("quitcheck"));
+  vb("'.\n"
+     "\n"
+     "Alternatively, you can edit the setup I have suggested, or use `");
+  vb(bindings->find("revertdirect"));
+  vb("' to reject my suggestions, before using `");
+  vb(bindings->find("quitcheck"));
+  vb("'.\n"
+     "\n"
+     "For a list of the keys available, consult the keymap "
+     "help screen (available by pressing `");
+  vb(bindings->find("help"));
+  vb("'); see the manual for detailed information.\n"
+     "\n"
+     "If you wish to replace a package on which many others depend with "
+     "a conflicting one you'll probably find it easier to try selecting "
+     "the new one rather than deselecting the old one first, as doing "
+     "the latter will cause me to suggest deselecting all that depend on it.");
+  wordwrapinfo(0,vb.string());
+}
+
+void methodlist::kd_info() {
+  showinghelp=0;
+  redrawinfo();
+}
+
+void methodlist::kd_help() {
+  if (showinghelp) ifhelpthenkeys= !ifhelpthenkeys;
+  showinghelp=1;
+  redrawinfo();
+}
+
+void methodlist::itd_welcome() {
+  whatinfovb("method selection welcome page");
+
+  varbuf vb;
+  vb("This is dselect's access method selection screen.");
+  vb("\n\n"
+     "Please press `");
+  vb(bindings->find("help"));
+  vb("' to show more help; in particular, you should read the list of "
+     "keystrokes; use `");
+  vb(bindings->find("iscrollon"));
+  vb("' and `");
+  vb(bindings->find("iscrollback"));
+  vb("' to scroll this help screen.  Press `");
+  vb(bindings->find("info"));
+  vb("' to see more information about the highlighted method.\n"
+     "\n");
+  vb("Move the highlight and use `");
+  vb(bindings->find("select-and-quit"));
+  vb("' to select the highlighted method.  Press `");
+  vb(bindings->find("abort"));
+  vb("' to abort without changing the access method.\n"
+     "\n"
+     "When you have selected the access method you will "
+     "be prompted for the information it requires to do the "
+     "installation.\n");
+  wordwrapinfo(0,vb.string());
+}
+
+  if (showinghelp)
+    if (ifhelpthenkeys)
+      itd_keys();
+    else
+      itd_welcome();
+  else
+
diff --git a/dselect/keyoverride b/dselect/keyoverride
new file mode 100644 (file)
index 0000000..4de681f
--- /dev/null
@@ -0,0 +1,59 @@
+# dselect - Debian GNU/Linux package maintenance user interface
+# keyoverride - override strings for ncurses key names
+#
+# Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+# This 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 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; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+32             Space
+13             Return
+27             Escape
+28             ^\
+29             ^]
+30             ^^
+31             ^_
+34             Quote
+39             Apostrophe
+44             Comma
+45             Hyphen
+47             Slash
+59             Semicolon
+92             Backslash
+96             Backquote
+127            DEL
+KEY_UP         Up
+KEY_DOWN       Down
+KEY_RIGHT      Right
+KEY_LEFT       Left
+KEY_IC         Insert
+KEY_SIC                Shift Insert
+KEY_DC         Delete
+KEY_SDC                Shift Delete
+KEY_NPAGE      Page Down
+KEY_PPAGE      Page Up
+KEY_CATAB      Clear Tabs
+KEY_EIC                EIC
+KEY_EOL                EOL
+KEY_SEOL       Shift EOL
+KEY_EOS                EOS
+KEY_LL         Bottom
+KEY_SF         Scroll Forward
+KEY_SR         Scroll Reverse
+KEY_SRESET     Soft Reset
+KEY_SLEFT      Shift Left
+KEY_SRIGHT     Shift Right
+KEY_SPREVIOUS  Shift Previous
+KEY_MAX                [elide]
+KEY_MIN                [elide]
diff --git a/dselect/keys.c b/dselect/keys.c
new file mode 100644 (file)
index 0000000..92dd16a
--- /dev/null
@@ -0,0 +1,91 @@
+{ KEY_MIN              , "MIN" },
+{ KEY_BREAK       , "BREAK" },
+{ KEY_DOWN        , "DOWN" },
+{ KEY_UP          , "UP" },
+{ KEY_LEFT        , "LEFT" },
+{ KEY_RIGHT       , "RIGHT" },
+{ KEY_HOME        , "HOME" },
+{ KEY_BACKSPACE   , "BACKSPACE" },
+{ KEY_F0          , "F0" },
+{ KEY_DL          , "DL" },
+{ KEY_IL          , "IL" },
+{ KEY_DC          , "DC" },
+{ KEY_IC          , "IC" },
+{ KEY_EIC         , "EIC" },
+{ KEY_CLEAR       , "CLEAR" },
+{ KEY_EOS         , "EOS" },
+{ KEY_EOL         , "EOL" },
+{ KEY_SF          , "SF" },
+{ KEY_SR          , "SR" },
+{ KEY_NPAGE       , "NPAGE" },
+{ KEY_PPAGE       , "PPAGE" },
+{ KEY_STAB        , "STAB" },
+{ KEY_CTAB        , "CTAB" },
+{ KEY_CATAB       , "CATAB" },
+{ KEY_ENTER       , "ENTER" },
+{ KEY_SRESET      , "SRESET" },
+{ KEY_RESET       , "RESET" },
+{ KEY_PRINT       , "PRINT" },
+{ KEY_LL          , "LL" },
+{ KEY_A1               , "A1" },
+{ KEY_A3               , "A3" },
+{ KEY_B2               , "B2" },
+{ KEY_C1               , "C1" },
+{ KEY_C3               , "C3" },
+{ KEY_BTAB     , "BTAB" },
+{ KEY_BEG              , "BEG" },
+{ KEY_CANCEL   , "CANCEL" },
+{ KEY_CLOSE    , "CLOSE" },
+{ KEY_COMMAND  , "COMMAND" },
+{ KEY_COPY     , "COPY" },
+{ KEY_CREATE   , "CREATE" },
+{ KEY_END              , "END" },
+{ KEY_EXIT     , "EXIT" },
+{ KEY_FIND     , "FIND" },
+{ KEY_HELP     , "HELP" },
+{ KEY_MARK     , "MARK" },
+{ KEY_MESSAGE  , "MESSAGE" },
+{ KEY_MOVE     , "MOVE" },
+{ KEY_NEXT     , "NEXT" },
+{ KEY_OPEN     , "OPEN" },
+{ KEY_OPTIONS  , "OPTIONS" },
+{ KEY_PREVIOUS , "PREVIOUS" },
+{ KEY_REDO     , "REDO" },
+{ KEY_REFERENCE        , "REFERENCE" },
+{ KEY_REFRESH  , "REFRESH" },
+{ KEY_REPLACE  , "REPLACE" },
+{ KEY_RESTART  , "RESTART" },
+{ KEY_RESUME   , "RESUME" },
+{ KEY_SAVE     , "SAVE" },
+{ KEY_SBEG     , "SBEG" },
+{ KEY_SCANCEL  , "SCANCEL" },
+{ KEY_SCOMMAND , "SCOMMAND" },
+{ KEY_SCOPY    , "SCOPY" },
+{ KEY_SCREATE  , "SCREATE" },
+{ KEY_SDC              , "SDC" },
+{ KEY_SDL              , "SDL" },
+{ KEY_SELECT   , "SELECT" },
+{ KEY_SEND     , "SEND" },
+{ KEY_SEOL     , "SEOL" },
+{ KEY_SEXIT    , "SEXIT" },
+{ KEY_SFIND    , "SFIND" },
+{ KEY_SHELP    , "SHELP" },
+{ KEY_SHOME    , "SHOME" },
+{ KEY_SIC              , "SIC" },
+{ KEY_SLEFT    , "SLEFT" },
+{ KEY_SMESSAGE , "SMESSAGE" },
+{ KEY_SMOVE    , "SMOVE" },
+{ KEY_SNEXT    , "SNEXT" },
+{ KEY_SOPTIONS , "SOPTIONS" },
+{ KEY_SPREVIOUS        , "SPREVIOUS" },
+{ KEY_SPRINT   , "SPRINT" },
+{ KEY_SREDO    , "SREDO" },
+{ KEY_SREPLACE , "SREPLACE" },
+{ KEY_SRIGHT   , "SRIGHT" },
+{ KEY_SRSUME   , "SRSUME" },
+{ KEY_SSAVE    , "SSAVE" },
+{ KEY_SSUSPEND , "SSUSPEND" },
+{ KEY_SUNDO    , "SUNDO" },
+{ KEY_SUSPEND  , "SUSPEND" },
+{ KEY_UNDO     , "UNDO" },
+{ KEY_MAX              , "MAX" },
diff --git a/dselect/kt.c b/dselect/kt.c
new file mode 100644 (file)
index 0000000..d322c68
--- /dev/null
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ncurses/curses.h>
+
+struct kd { int v; const char *n; } kds[]= {
+#include "curkeys.inc"
+};
+
+int main(int argc, char **argv) {
+  int n=0, c, y,x;
+  struct kd *kdp;
+
+  initscr(); cbreak(); noecho(); nonl();
+  keypad(stdscr,TRUE);
+  getmaxyx(stdscr,y,x);
+  mvprintw(5,5,"q to quit; b to beep; (y%d x%d)",y,x);
+
+  for (;;) {
+    refresh();
+    c= getch(); if (c==ERR) { endwin(); perror("err"); exit(1); }
+    for (kdp=kds; kdp->v != -1 && kdp->v != c; kdp++);
+    n++; mvprintw(10 + (n%4),10,"n %10d  keycode %4d  %-10s  F0 + %4d",n,c,
+                  kdp->n ? kdp->n : "<none>", c-KEY_F0);
+    if (c == 'q') break;
+    if (c == 'b') beep();
+  }
+  endwin();
+  return 0;
+}
diff --git a/dselect/kt.cc b/dselect/kt.cc
new file mode 100644 (file)
index 0000000..d448a58
--- /dev/null
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ncurses/curses.h>
+
+struct kd { int v; const char *n; } kds[]= {
+#include "curkeys.inc"
+};
+
+int main(int argc, char **argv) {
+  int n=0, c, y,x;
+  struct kd *kdp;
+
+  initscr(); cbreak(); noecho(); nonl();
+  keypad(stdscr,TRUE);
+  getmaxyx(stdscr,y,x);
+  mvprintw(5,5,"q to quit; b to beep; (y%d x%d)",y,x);
+
+  for (;;) {
+    refresh();
+    c= getch(); if (c==ERR) { endwin(); perror("err"); exit(1); }
+    for (kdp=kds; kdp->v != -1 && kdp->v != c; kdp++);
+    n++; mvprintw(10 + (n%4),10,"n %10d  keycode %4d  %-10s  F0 + %4d",n,c,
+                  kdp->n, c-KEY_F0);
+    if (c == 'q') break;
+    if (c == 'b') beep();
+  }
+  endwin();
+  return 0;
+}
diff --git a/dselect/main.cc b/dselect/main.cc
new file mode 100644 (file)
index 0000000..e65f635
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * main.cc - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <ncurses.h>
+#include <term.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "version.h"
+#include "myopt.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "pkglist.h"
+
+const char thisname[]= DSELECT;
+const char printforhelp[]= "Type " DPKG " --help for help.";
+
+modstatdb_rw readwrite;
+const char *admindir= ADMINDIR;
+FILE *debug;
+
+static keybindings packagelistbindings(packagelist_kinterps,packagelist_korgbindings);
+
+struct menuentry {
+  const char *option;
+  const char *menuent;
+  urqfunction *fn;
+};
+
+static const menuentry menuentries[]= {
+  { "access",  "Choose the access method to use.",                 &urq_setup   },
+  { "update",  "Update list of available packages, if possible.",  &urq_update  },
+  { "select",  "Select which packages to install (or deinstall).", &urq_list    },
+  { "install", "Install selected software.",                       &urq_install },
+  { "config",  "Configure packages that are unconfigured.",        &urq_config  },
+  { "remove",  "Remove software selected for deinstallation.",     &urq_remove  },
+  { "quit",    "Quit dselect.",                                    &urq_quit    },
+  { "menu",     0,                                                 &urq_menu    },
+  {  0                                                                          }
+};
+
+static const char programdesc[]=
+      "Debian GNU/Linux `" DSELECT "' package handling frontend.";
+
+static const char copyrightstring[]=
+      "Version " DPKG_VERSION_ARCH ".  Copyright (C) 1994,1995 Ian Jackson.   This is\n"
+      "free software; see the GNU General Public Licence version 2 or later for\n"
+      "copying conditions.  There is NO warranty.  See dselect --licence for details.\n";
+
+static void printversion(void) {
+  if (fprintf(stderr,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs
+      ("Usage: dselect [options]\n"
+       "       dselect [options] action ...\n"
+       "Options:  --admindir <directory>  (default is /var/lib/dpkg)\n"
+       "          --help  --version  --licence   --debug <file> | -D<file> | -D\n"
+       "Actions:  access update select install config remove quit menu\n",
+       stderr)) werr("stderr");
+}
+
+/* These are called by C code, so need to have C calling convention */
+extern "C" {
+
+  static void helponly(const struct cmdinfo*, const char*) {
+    usage(); exit(0);
+  }
+  static void versiononly(const struct cmdinfo*, const char*) {
+    printversion(); exit(0);
+  }
+
+  static void setdebug(const struct cmdinfo*, const char *v) {
+    debug= fopen(v,"a");
+    if (!debug) ohshite("couldn't open debug file `%.255s'\n",v);
+    setvbuf(debug,0,_IONBF,0);
+  }
+
+} /* End of extern "C" */
+
+static const struct cmdinfo cmdinfos[]= {
+  { "admindir",   0,   1,  0,  &admindir,  0                      },
+  { "debug",     'D',  1,  0,  0,          setdebug               },
+  { "help",      'h',  0,  0,  0,          helponly               },
+  { "version",    0,   0,  0,  0,          versiononly            },
+  { "licence",    0,   0,  0,  0,          showcopyright          }, /* UK spelling */
+  { "license",    0,   0,  0,  0,          showcopyright          }, /* US spelling */
+  {  0,           0                                               }
+};
+
+static int cursesareon= 0;
+void curseson() {
+  if (!cursesareon) {
+    const char *cup, *smso;
+    initscr();
+    cup= tigetstr("cup");
+    smso= tigetstr("smso");
+    if (!cup || !smso) {
+      endwin();
+      if (!cup)
+        fputs("Terminal does not appear to support cursor addressing.\n",stderr);
+      if (!smso)
+        fputs("Terminal does not appear to support highlighting.\n",stderr);
+      fputs("Set your TERM variable correctly, use a better terminal,\n"
+            "or make do with the per-package management tool " DPKG ".\n",stderr);
+      ohshit("terminal lacks necessary features, giving up");
+    }
+  }
+  cursesareon= 1;
+}
+
+void cursesoff() {
+  if (cursesareon) {
+    clear();
+    refresh();
+    endwin();
+  }
+  cursesareon=0;
+}
+
+extern void *operator new(size_t size) {
+  void *p;
+  p= m_malloc(size);
+  assert(p);
+  return p;
+}
+
+extern void operator delete(void *p) {
+  free(p);
+}
+
+urqresult urq_list(void) {
+  readwrite= modstatdb_init(admindir,
+                            msdbrw_writeifposs|msdbrw_availablepreferversion);
+
+  curseson();
+
+  packagelist *l= new packagelist(&packagelistbindings);
+  l->resolvesuggest();
+  l->display();
+  delete l;
+
+  modstatdb_shutdown();
+  resetpackages();
+  return urqr_normal;
+}
+
+void dme(int i, int so) {
+  char buf[120];
+  const menuentry *me= &menuentries[i];
+  sprintf(buf," %c %d. [%c]%-10.10s %-80.80s ",
+          so ? '*' : ' ', i,
+          toupper(me->option[0]), me->option+1,
+          me->menuent);
+  
+  int y,x;
+  getmaxyx(stdscr,y,x);
+
+  attrset(so ? A_REVERSE : A_NORMAL);
+  mvaddnstr(i+2,0, buf,x-1);
+  attrset(A_NORMAL);
+}
+
+int refreshmenu(void) {
+  curseson(); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
+
+  int y,x;
+  getmaxyx(stdscr,y,x);
+
+  clear();
+  attrset(A_BOLD);
+  mvaddnstr(0,0, programdesc,x-1);
+
+  attrset(A_NORMAL);
+  const struct menuentry *mep; int i;
+  for (mep=menuentries, i=0; mep->option && mep->menuent; mep++, i++)
+    dme(i,0);
+
+  attrset(A_BOLD);
+  addstr("\n\n"
+         "Use ^P and ^N, cursor keys, initial letters, or digits to select;\n"
+         "Press ENTER to confirm selection.   ^L to redraw screen.\n\n");
+
+  attrset(A_NORMAL);
+  addstr(copyrightstring);
+
+  return i;
+}
+
+urqresult urq_menu(void) {
+#define C(x) ((x)-'a'+1)
+  int entries, c, i;
+  entries= refreshmenu();
+  int cursor=0;
+  dme(0,1);
+  for (;;) {
+    refresh();
+    c= getch();  if (c==ERR) ohshite("failed to getch in main menu");
+    if (c==C('n') || c==KEY_DOWN || c==' ') {
+      dme(cursor,0); cursor++; cursor %= entries; dme(cursor,1);
+    } else if (c==C('p') || c==KEY_UP || c==C('h') ||
+               c==KEY_BACKSPACE || c==KEY_DC) {
+      dme(cursor,0); cursor+= entries-1; cursor %= entries; dme(cursor,1);
+    } else if (c=='\n' || c=='\r' || c==KEY_ENTER) {
+      clear(); refresh();
+      switch (menuentries[cursor].fn()) { /* fixme: trap errors in urq_... */
+      case urqr_quitmenu:
+        return urqr_quitmenu;
+      case urqr_normal:
+        cursor++; cursor %= entries;
+      case urqr_fail:
+        break;
+      default:
+        internerr("unknown menufn");
+      }
+      refreshmenu(); dme(cursor,1);
+    } else if (c==C('l')) {
+      clearok(stdscr,TRUE); clear(); refreshmenu(); dme(cursor,1);
+    } else if (isdigit(c)) {
+      char buf[2]; buf[0]=c; buf[1]=0; c=atoi(buf);
+      if (c < entries) {
+        dme(cursor,0); cursor=c; dme(cursor,1);
+      } else {
+        beep();
+      }
+    } else if (isalpha(c)) {
+      c= tolower(c);
+      for (i=0; i<entries && menuentries[i].option[0] != c; i++);
+      if (i < entries) {
+        dme(cursor,0); cursor=i; dme(cursor,1);
+      } else {
+        beep();
+      }
+    } else {
+      beep();
+    }
+  }
+}
+
+urqresult urq_quit(void) {
+  return urqr_quitmenu;
+  /* fixme: check packages OK */
+}
+
+int main(int, const char *const *argv) {
+  jmp_buf ejbuf;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    cursesoff();
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  myopt(&argv,cmdinfos);
+
+  if (*argv) {
+    const char *a;
+    while ((a= *argv++) != 0) {
+      const menuentry *me;
+      for (me= menuentries; me->option && strcmp(me->option,a); me++);
+      if (!me->option) badusage("unknown action string `%.50s'",a);
+      me->fn();
+    }
+  } else {
+    urq_menu();
+  }
+
+  cursesoff();
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+  return(0);
+}
diff --git a/dselect/methkeys.cc b/dselect/methkeys.cc
new file mode 100644 (file)
index 0000000..eef8104
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methkeys.cc - method list keybindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::interpretation methodlist_kinterps[] = {
+  { "up",              methodlist::kd_up,             0,    qa_noquit           },
+  { "down",            methodlist::kd_down,           0,    qa_noquit           },
+  { "top",             methodlist::kd_top,            0,    qa_noquit           },
+  { "bottom",          methodlist::kd_bottom,         0,    qa_noquit           },
+  { "scrollon",        methodlist::kd_scrollon,       0,    qa_noquit           },
+  { "scrollback",      methodlist::kd_scrollback,     0,    qa_noquit           },
+  { "iscrollon",       methodlist::kd_iscrollon,      0,    qa_noquit           },
+  { "iscrollback",     methodlist::kd_iscrollback,    0,    qa_noquit           },
+  { "scrollon1",       methodlist::kd_scrollon1,      0,    qa_noquit           },
+  { "scrollback1",     methodlist::kd_scrollback1,    0,    qa_noquit           },
+  { "iscrollon1",      methodlist::kd_iscrollon1,     0,    qa_noquit           },
+  { "iscrollback1",    methodlist::kd_iscrollback1,   0,    qa_noquit           },
+  { "panon",           methodlist::kd_panon,          0,    qa_noquit           },
+  { "panback",         methodlist::kd_panback,        0,    qa_noquit           },
+  { "panon1",          methodlist::kd_panon1,         0,    qa_noquit           },
+  { "panback1",        methodlist::kd_panback1,       0,    qa_noquit           },
+  { "help",            methodlist::kd_help,           0,    qa_noquit           },
+  { "search",          methodlist::kd_search,         0,    qa_noquit           },
+  { "searchagain",     methodlist::kd_searchagain,    0,    qa_noquit           },
+  { "redraw",          methodlist::kd_redraw,         0,    qa_noquit           },
+  { "select-and-quit", methodlist::kd_quit,           0,    qa_quitchecksave    },
+  { "abort",           methodlist::kd_abort,          0,    qa_quitnochecksave  },
+  {  0,                0,                                   qa_noquit           }
+};
+
+#define C(x) ((x)-'a'+1)
+
+const keybindings::orgbinding methodlist_korgbindings[]= {
+  { 'n',            "down"           },
+  { KEY_DOWN,       "down"           },
+  { 'p',            "up"             },
+  { KEY_UP,         "up"             },
+  
+  { 'N',            "scrollon"       },
+  { KEY_NPAGE,      "scrollon"       },
+  { ' ',            "scrollon"       },
+  { 'P',            "scrollback"     },
+  { KEY_PPAGE,      "scrollback"     },
+  { KEY_BACKSPACE,  "scrollback"     },
+  { 0177,/*DEL*/    "scrollback"     },
+  { C('h'),         "scrollback"     },
+  { C('n'),         "scrollon1"      },
+  { C('p'),         "scrollback1"    },
+  
+  { 't',            "top"            },
+  { KEY_HOME,       "top"            },
+  { 'e',            "bottom"         },
+  { KEY_LL,         "bottom"         },
+  { KEY_END,        "bottom"         },
+  
+  { 'u',            "iscrollback"    },
+  { 'd',            "iscrollon"      },
+  { C('u'),         "iscrollback1"   },
+  { C('d'),         "iscrollon1"     },
+  
+  { 'B',            "panback"        },
+  { KEY_LEFT,       "panback"        },
+  { 'F',            "panon"          },
+  { KEY_RIGHT,      "panon"          },
+  { C('b'),         "panback1"       },
+  { C('f'),         "panon1"         },
+                                      
+  { '?',            "help"             },
+  { KEY_HELP,       "help"             },
+  { KEY_F(1),       "help"             },
+  { '/',            "search"           },
+  { '\\',           "searchagain"      },
+  { C('l'),         "redraw"           },
+
+  { KEY_ENTER,      "select-and-quit"  },
+  { '\r',           "select-and-quit"  },
+  { 'x',            "abort"            },
+  { 'X',            "abort"            },
+  
+  {  -1,             0                 }
+};
diff --git a/dselect/methlist.cc b/dselect/methlist.cc
new file mode 100644 (file)
index 0000000..710fabf
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methlist.cc - list of access methods and options
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "method.h"
+#include "helpmsgs.h"
+
+static keybindings methodlistbindings(methodlist_kinterps,methodlist_korgbindings);
+
+const char *methodlist::itemname(int index) {
+  return table[index]->name;
+}
+
+void methodlist::kd_abort() { }
+
+void methodlist::kd_quit() {
+  if (debug) fprintf(debug,"methodlist[%p]::kd_quit() setting coption=%p\n",
+                     this, table[cursorline]);
+  coption= table[cursorline];
+}
+
+void methodlist::setwidths() {
+  if (debug) fprintf(debug,"methodlist[%p]::setwidths()\n",this);
+
+  status_width= 1;
+  gap_width= 1;
+  name_width= 14;
+  name_column= status_width + gap_width;
+  description_column= name_column + name_width + gap_width;
+
+  total_width= TOTAL_LIST_WIDTH;
+  description_width= total_width - description_column;
+}
+
+void methodlist::redrawtitle() {
+  if (title_height) {
+    mywerase(titlewin);
+    mvwaddnstr(titlewin,0,0,"dselect - list of access methods",xmax);
+    wnoutrefresh(titlewin);
+  }
+}
+
+void methodlist::redrawthisstate() {
+  if (!thisstate_height) return;
+  mywerase(thisstatepad);
+  wprintw(thisstatepad,
+          "Access method `%s'.",
+          table[cursorline]->name);
+  pnoutrefresh(thisstatepad, 0,0, thisstate_row,0,
+               thisstate_row, lesserint(total_width - 1, xmax - 1));
+}
+
+void methodlist::redraw1itemsel(int index, int selected) {
+  int i;
+  const char *p;
+
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+  mvwaddch(listpad,index,0,
+           table[index] == coption ? '*' : ' ');
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+  mvwprintw(listpad,index,name_column-1, " %-*.*s ",
+            name_width, name_width, table[index]->name);
+  
+  i= description_width;
+  p= table[index]->summary ? table[index]->summary : "";
+  while (i>0 && *p && *p != '\n') {
+    waddch(listpad,*p);
+    i--; p++;
+  }
+  while (i>0) {
+    waddch(listpad,' ');
+    i--;
+  }
+}
+
+void methodlist::redrawcolheads() {
+  if (colheads_height) {
+    wattrset(colheadspad,colheads_attr);
+    mywerase(colheadspad);
+    mvwaddstr(colheadspad,0,0, "  ");
+    mvwaddnstr(colheadspad,0,name_column, "Abbrev.", name_width);
+    mvwaddnstr(colheadspad,0,description_column, "Description", description_width);
+  }
+  refreshcolheads();
+}
+
+methodlist::methodlist() : baselist(&methodlistbindings) {
+  if (debug)
+    fprintf(debug,"methodlist[%p]::methodlist()\n",this);
+
+  table= new struct option*[noptions];
+
+  struct option *opt, **ip;
+  for (opt=options, ip=table, nitems=0; opt; opt=opt->next, nitems++) *ip++= opt;
+  assert(nitems==noptions);
+
+  setcursor(0);
+
+  if (debug)
+    fprintf(debug,"methodlist[%p]::methodlist done; noptions=%d\n", this, noptions);
+}
+
+methodlist::~methodlist() {
+  if (debug) fprintf(debug,"methodlist[%p]::~methodlist()\n",this);
+  delete[] table;
+}
+
+quitaction methodlist::display() {
+  int response;
+  const keybindings::interpretation *interp;
+
+  if (debug) fprintf(debug,"methodlist[%p]::display()\n",this);
+
+  setupsigwinch();
+  startdisplay();
+  
+  if (debug) fprintf(debug,"methodlist[%p]::display() entering loop\n",this);
+  for (;;) {
+    if (whatinfo_height) wcursyncup(whatinfowin);
+    if (doupdate() == ERR) ohshite("doupdate failed");
+    signallist= this;
+    if (sigprocmask(SIG_UNBLOCK,&sigwinchset,0)) ohshite("failed to unblock SIGWINCH");
+    response= getch();
+    if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to re-block SIGWINCH");
+    if (response == ERR) ohshite("getch failed");
+    interp= (*bindings)(response);
+    if (debug)
+      fprintf(debug,"methodlist[%p]::display() response=%d interp=%s\n",
+              this,response, interp ? interp->action : "[none]");
+    if (!interp) { beep(); continue; }
+    (this->*(interp->mfn))();
+    if (interp->qa != qa_noquit) break;
+  }
+  pop_cleanup(ehflag_normaltidy); // unset the SIGWINCH handler
+  enddisplay();
+  
+  if (debug) fprintf(debug,"methodlist[%p]::display() done\n",this);
+
+  return interp->qa;
+}
+
+void methodlist::itd_description() {
+  whatinfovb("explanation of ");
+  whatinfovb(table[cursorline]->name);
+
+  wattrset(infopad,info_headattr);
+  waddstr(infopad, table[cursorline]->name);
+  waddstr(infopad," - ");
+  waddstr(infopad, table[cursorline]->summary);
+  wattrset(infopad,info_attr);
+
+  const char *m= table[cursorline]->description;
+  if (!m || !*m) m= "No explanation available.";
+  waddstr(infopad,"\n\n");
+  wordwrapinfo(0,m);
+}
+
+void methodlist::redrawinfo() {
+  if (!info_height) return;
+  whatinfovb.reset();
+  werase(infopad); wmove(infopad,0,0);
+  
+  if (debug) fprintf(debug,"methodlist[%p]::redrawinfo()\n", this);
+
+  itd_description();
+
+  whatinfovb.terminate();
+  int y,x;
+  getyx(infopad, y,x);
+  if (x) y++;
+  infolines= y;
+
+  refreshinfo();
+}
+
+const struct helpmenuentry *methodlist::helpmenulist() {
+  static const struct helpmenuentry list[]= {
+    { 'i', &hlp_methintro            },
+    { 'k', &hlp_methkeys             },
+    {  0                             }
+  };
+  return list;
+};
diff --git a/dselect/method.cc b/dselect/method.cc
new file mode 100644 (file)
index 0000000..67939eb
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * method.cc - access method handling
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/file.h>
+
+#include <ncurses.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "method.h"
+
+static const char *const methoddirectories[]= {
+  LIBDIR "/" METHODSDIR,
+  LOCALLIBDIR "/" METHODSDIR,
+  0
+};    
+
+static char *methodlockfile= 0;
+static int methlockfd= -1;
+
+static void cu_unlockmethod(int, void**) {
+  assert(methodlockfile);
+  assert(methlockfd);
+  if (flock(methlockfd,LOCK_UN))
+    ohshite("unable to unlock access method area");
+}
+
+static enum urqresult ensureoptions(void) {
+  const char *const *ccpp;
+  option *newoptions;
+  int nread;
+
+  if (!options) {
+    newoptions= 0;
+    nread= 0;
+    for (ccpp= methoddirectories; *ccpp; ccpp++)
+      readmethods(*ccpp, &newoptions, &nread);
+    if (!newoptions) {
+      curseson();
+      addstr("No access methods are available.\n\n"
+             "Press RETURN to continue.");
+      refresh(); getch();
+      return urqr_fail;
+    }
+    options= newoptions;
+    noptions= nread;
+  }
+  return urqr_normal;
+}
+
+static void lockmethod(void) {
+  if (!methodlockfile) {
+    int l;
+    l= strlen(admindir);
+    methodlockfile= new char[l+sizeof(METHLOCKFILE)+2];
+    strcpy(methodlockfile,admindir);
+    strcpy(methodlockfile+l, "/" METHLOCKFILE);
+  }
+  if (methlockfd == -1) {
+    methlockfd= open(methodlockfile, O_RDWR|O_CREAT|O_TRUNC, 0660);
+    if (methlockfd == -1) {
+      if (errno == EPERM)
+        ohshit("you do not have permission to change the access method");
+      ohshite("unable to open/create access method lockfile");
+    }
+  }
+  if (flock(methlockfd,LOCK_EX|LOCK_NB)) {
+    if (errno == EWOULDBLOCK || errno == EAGAIN)
+      ohshit("the access method area is already locked");
+    ohshite("unable to lock access method area");
+  }
+  push_cleanup(cu_unlockmethod,~0, 0,0, 0);
+}
+
+static int catchsignals[]= { SIGQUIT, SIGINT, 0 };
+#define NCATCHSIGNALS ((signed)(sizeof(catchsignals)/sizeof(int))-1)
+static struct sigaction uncatchsignal[NCATCHSIGNALS];
+
+void cu_restoresignals(int, void**) {
+  int i;
+  for (i=0; i<NCATCHSIGNALS; i++)
+    if (sigaction(catchsignals[i],&uncatchsignal[i],0))
+      fprintf(stderr,"error un-catching signal %d: %s\n",
+              catchsignals[i],strerror(errno));
+}
+
+urqresult falliblesubprocess(const char *exepath, const char *name,
+                             const char *const *args) {
+  pid_t c1, cr;
+  int status, i, c;
+  struct sigaction catchsig;
+  
+  cursesoff();
+
+  memset(&catchsig,0,sizeof(catchsig));
+  catchsig.sa_handler= SIG_IGN;
+  sigemptyset(&catchsig.sa_mask);
+  catchsig.sa_flags= 0;
+  for (i=0; i<NCATCHSIGNALS; i++)
+    if (sigaction(catchsignals[i],&catchsig,&uncatchsignal[i]))
+      ohshite("unable to ignore signal %d before running %.250s",
+              catchsignals[i], name);
+  push_cleanup(cu_restoresignals,~0, 0,0, 0);
+
+  if (!(c1= m_fork())) {
+    cu_restoresignals(0,0);
+    execvp(exepath,(char* const*) args);
+    ohshite("unable to run %.250s process `%.250s'",name,exepath);
+  }
+
+  while ((cr= waitpid(c1,&status,0)) == -1)
+    if (errno != EINTR) ohshite("unable to wait for %.250s",name);
+  if (cr != c1)
+    ohshit("got wrong child's status - asked for %ld, got %ld",(long)c1,(long)cr);
+
+  pop_cleanup(ehflag_normaltidy);
+
+  if (WIFEXITED(status) && !WEXITSTATUS(status)) {
+    sleep(1);
+    return urqr_normal;
+  }
+  fprintf(stderr,"\n%s ",name);
+  if (WIFEXITED(status)) {
+    i= WEXITSTATUS(status);
+    fprintf(stderr,"returned error exit status %d.\n",i);
+  } else if (WIFSIGNALED(status)) {
+    i= WTERMSIG(status);
+    if (i == SIGINT) {
+      fprintf(stderr,"was interrupted.\n");
+    } else {
+      fprintf(stderr,"was terminated by a signal: %s.\n",strsignal(i));
+    }
+    if (WCOREDUMP(status))
+      fprintf(stderr,"(It left a coredump.)\n");
+  } else {
+    fprintf(stderr,"failed with an unknown wait return code %d.\n",status);
+  }
+  fprintf(stderr,"Press RETURN to continue.\n");
+  if (ferror(stderr))
+    ohshite("write error on standard error");
+  do { c= fgetc(stdin); } while (c != EOF && c != '\n');
+  if (c == EOF)
+    ohshite("error reading acknowledgement of program failure message");
+  return urqr_fail;
+}
+
+static urqresult runscript(const char *exepath, const char *name) {
+  urqresult ur;  
+
+  ur= ensureoptions();  if (ur != urqr_normal) return ur;
+  lockmethod();
+  getcurrentopt();
+
+  if (coption) {
+    strcpy(coption->meth->pathinmeth,exepath);
+    const char *fallibleargs[] = {
+      exepath,
+      admindir,
+      coption->meth->name,
+      coption->name,
+      0
+      };
+    ur= falliblesubprocess(coption->meth->path,name,fallibleargs);
+  } else {
+    curseson();
+    addstr("No access method is selected/configured.\n\n"
+           "Press RETURN to continue.");
+    refresh(); getch();
+    ur= urqr_fail;
+  }
+  pop_cleanup(ehflag_normaltidy);
+
+  return ur;
+}
+
+urqresult urq_update(void) {
+  return runscript(METHODUPDATESCRIPT,"update available list script");
+}
+
+urqresult urq_install(void) {
+  return runscript(METHODINSTALLSCRIPT,"installation script");
+}
+
+static urqresult rundpkgauto(const char *name, const char *dpkgmode) {
+  const char *fallibleargs[] = {
+    DPKG,
+    "--pending",
+    dpkgmode,
+    0
+  };
+  cursesoff();
+  printf("running dpkg --pending %s ...\n",dpkgmode);
+  fflush(stdout);
+  return falliblesubprocess(DPKG,name,fallibleargs);
+}
+
+urqresult urq_remove(void) {
+  return rundpkgauto("dpkg --remove","--remove");
+}
+
+urqresult urq_config(void) {
+  return rundpkgauto("dpkg --configure","--configure");
+}
+
+urqresult urq_setup(void) {
+  quitaction qa;
+  urqresult ur;
+
+  ur= ensureoptions();  if (ur != urqr_normal) return ur;
+  lockmethod();  
+  getcurrentopt();
+
+  curseson();
+  methodlist *l= new methodlist();
+  qa= l->display();
+  delete l;
+
+  if (qa == qa_quitchecksave) {
+    strcpy(coption->meth->pathinmeth,METHODSETUPSCRIPT);
+    const char *fallibleargs[] = {
+      METHODSETUPSCRIPT,
+      admindir,
+      coption->meth->name,
+      coption->name,
+      0
+    };
+    ur= falliblesubprocess(coption->meth->path,"query/setup script",fallibleargs);
+    if (ur == urqr_normal) writecurrentopt();
+  } else {
+    ur= urqr_fail;
+  }
+  
+  pop_cleanup(ehflag_normaltidy);
+  return ur;
+}
diff --git a/dselect/method.h b/dselect/method.h
new file mode 100644 (file)
index 0000000..7482044
--- /dev/null
@@ -0,0 +1,79 @@
+/* -*- c++ -*-
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * method.h - access method handling declarations
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef METHOD_H
+#define METHOD_H
+
+struct method {
+  struct method *next, *back;
+  char *name, *path, *pathinmeth;
+};
+
+struct option {
+  option *next;
+  method *meth;
+  char index[OPTIONINDEXMAXLEN];
+  char *name, *summary;
+  char *description;
+};
+
+class methodlist : public baselist {
+  int status_width, gap_width, name_width, description_width;
+  int name_column, description_column;
+
+  // Table of methods
+  struct option **table;
+
+  // Misc.
+  char searchstring[50];
+  
+  // Information displays
+  void itd_description();
+  
+  // Define these virtuals
+  void redraw1itemsel(int index, int selected);
+  void redrawcolheads();
+  void redrawthisstate();
+  void redrawinfo();
+  void redrawtitle();
+  void setwidths();
+  const char *itemname(int index);
+  const struct helpmenuentry *helpmenulist();
+
+ public:
+  // Keybinding functions */
+  void kd_quit();
+  void kd_abort();
+  
+  methodlist();
+  quitaction display();
+  ~methodlist();
+};
+
+extern int noptions;
+extern struct option *options, *coption;
+extern struct method *methods;
+
+extern void readmethods(const char *pathbase, option **optionspp, int *nread);
+extern void getcurrentopt();
+extern void writecurrentopt();
+
+#endif /* METHOD_H */
diff --git a/dselect/methparse.cc b/dselect/methparse.cc
new file mode 100644 (file)
index 0000000..02e51b4
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methparse.cc - access method list parsing
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <ncurses.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+int noptions=0;
+struct option *options=0, *coption=0;
+struct method *methods=0;
+
+static void badmethod(const char *pathname, const char *why) __NORETURN;
+static void badmethod(const char *pathname, const char *why) {
+  ohshit("syntax error in method options file `%.250s' -- %s", pathname, why);
+}
+
+static void eofmethod(const char *pathname, FILE *f, const char *why) __NORETURN;
+static void eofmethod(const char *pathname, FILE *f, const char *why) {
+  if (ferror(f)) ohshite("error reading options file `%.250s'",pathname);
+  badmethod(pathname,why);
+}
+
+void readmethods(const char *pathbase, option **optionspp, int *nread) {
+  static const char *const methodprograms[]= {
+    METHODSETUPSCRIPT, METHODUPDATESCRIPT, METHODINSTALLSCRIPT, 0
+  };
+  const char *const *ccpp;
+  int methodlen, c, baselen;
+  char *p, *pathinmeth, *pathbuf, *pathmeth;
+  DIR *dir;
+  FILE *names, *descfile;
+  struct dirent *dent;
+  struct varbuf vb;
+  method *meth;
+  option *opt, **optinsert;
+  struct stat stab;
+
+  baselen= strlen(pathbase);
+  pathbuf= new char[baselen+IMETHODMAXLEN+IOPTIONMAXLEN+sizeof(OPTIONSDESCPFX)+10];
+  strcpy(pathbuf,pathbase);
+  strcpy(pathbuf+baselen,"/");
+  pathmeth= pathbuf+baselen+1;
+
+  dir= opendir(pathbuf);
+  if (!dir) {
+    if (errno == ENOENT) return;
+    ohshite("unable to read `%.250s' directory for reading methods",pathbuf);
+  }
+
+  if (debug) fprintf(debug,"readmethods(`%s',...) directory open\n", pathbase);
+  
+  while ((dent= readdir(dir)) != 0) {
+    c= dent->d_name[0];
+    if (debug) fprintf(debug,"readmethods(`%s',...) considering `%s' ...\n",
+                       pathbase,dent->d_name);
+    if (c != '_' && !isalpha(c)) continue;
+    for (p= dent->d_name+1; (c= *p) != 0 && isalnum(c) && c != '_'; p++);
+    if (c) continue;
+    methodlen= strlen(dent->d_name);
+    if (methodlen > IMETHODMAXLEN)
+      ohshit("method `%.250s' has name that is too long (%d > %d characters)",
+             dent->d_name, methodlen, IMETHODMAXLEN);
+    strcpy(pathmeth, dent->d_name);
+    strcpy(pathmeth+methodlen, "/");
+    pathinmeth= pathmeth+methodlen+1;
+
+    for (ccpp= methodprograms; *ccpp; ccpp++) {
+      strcpy(pathinmeth,*ccpp);
+      if (access(pathbuf,R_OK|X_OK))
+        ohshite("unable to access method script `%.250s'",pathbuf);
+    }
+    if (debug) fprintf(debug," readmethods(`%s',...) scripts ok\n", pathbase);
+
+    strcpy(pathinmeth,METHODOPTIONSFILE);
+    names= fopen(pathbuf,"r");
+    if (!names) ohshite("unable to read method options file `%.250s'",pathbuf);
+
+    meth= new method;
+    meth->name= new char[strlen(dent->d_name)+1];
+    strcpy(meth->name,dent->d_name);
+    meth->path= new char[baselen+1+methodlen+2+50];
+    strncpy(meth->path,pathbuf,baselen+1+methodlen);
+    strcpy(meth->path+baselen+1+methodlen,"/");
+    meth->pathinmeth= meth->path+baselen+1+methodlen+1;
+    meth->next= methods;
+    meth->back= 0;
+    if (methods) methods->back= meth;
+    methods= meth;
+    if (debug) fprintf(debug," readmethods(`%s',...) new method"
+                       " name=`%s' path=`%s' pathinmeth=`%s'\n",
+                       pathbase, meth->name, meth->path, meth->pathinmeth);
+    
+    while ((c= fgetc(names)) != EOF) {
+      if (isspace(c)) continue;
+      opt= new option;
+      opt->meth= meth;
+      vb.reset();
+      do {
+        if (!isdigit(c)) badmethod(pathbuf,"non-digit where digit wanted");
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in index string");
+      } while (!isspace(c));
+      if (strlen(vb.string()) > OPTIONINDEXMAXLEN)
+        badmethod(pathbuf,"index string too long");
+      strcpy(opt->index,vb.string());
+      do {
+        if (c == '\n') badmethod(pathbuf,"newline before option name start");
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF before option name start");
+      } while (isspace(c));
+      vb.reset();
+      if (!isalpha(c) && c != '_')
+        badmethod(pathbuf,"nonalpha where option name start wanted");
+      do {
+        if (!isalnum(c) && c != '_') badmethod(pathbuf,"non-alphanum in option name");
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in option name");
+      } while (!isspace(c));
+      opt->name= new char[strlen(vb.string())+1];
+      strcpy(opt->name,vb.string());
+      do {
+        if (c == '\n') badmethod(pathbuf,"newline before summary");
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF before summary");
+      } while (isspace(c));
+      vb.reset();
+      do {
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in summary - missing newline");
+      } while (c != '\n');
+      opt->summary= new char[strlen(vb.string())+1];
+      strcpy(opt->summary,vb.string());
+      
+      strcpy(pathinmeth,OPTIONSDESCPFX);
+      strcpy(pathinmeth+sizeof(OPTIONSDESCPFX)-1,opt->name);
+      descfile= fopen(pathbuf,"r");
+      if (!descfile) {
+        if (errno != ENOENT)
+          ohshite("unable to open option description file `%.250s'",pathbuf);
+        opt->description= 0;
+      } else { /* descfile != 0 */
+        if (fstat(fileno(descfile),&stab))
+          ohshite("unable to stat option description file `%.250s'",pathbuf);
+        opt->description= new char[stab.st_size+1];  errno=0;
+        if (fread(opt->description,1,stab.st_size+1,descfile) != stab.st_size)
+          ohshite("failed to read option description file `%.250s'",pathbuf);
+        opt->description[stab.st_size]= 0;
+        if (ferror(descfile))
+          ohshite("error during read of option description file `%.250s'",pathbuf);
+        fclose(descfile);
+      }
+      strcpy(pathinmeth,METHODOPTIONSFILE);
+      
+      if (debug) fprintf(debug," readmethods(`%s',...) new option"
+                         " index=`%s' name=`%s' summary=`%.20s'"
+                         " strlen(description=%s)=%d"
+                         " method name=`%s' path=`%s' pathinmeth=`%s'\n",
+                         pathbase,
+                         opt->index, opt->name, opt->summary,
+                         opt->description ? "`...'" : "null",
+                         opt->description ? strlen(opt->description) : -1,
+                         opt->meth->name, opt->meth->path, opt->meth->pathinmeth);
+      for (optinsert= optionspp;
+           *optinsert && strcmp(opt->index,(*optinsert)->index) > 0;
+           optinsert= &(*optinsert)->next);
+      opt->next= *optinsert;
+      *optinsert= opt;
+      (*nread)++;
+    }
+    if (ferror(names))
+      ohshite("error during read of method options file `%.250s'",pathbuf);
+    fclose(names);
+  }
+  closedir(dir);
+  if (debug) fprintf(debug,"readmethods(`%s',...) done\n", pathbase);
+  delete[] pathbuf;
+}
+
+static char *methoptfile= 0;
+
+void getcurrentopt() {
+  char methoptbuf[IMETHODMAXLEN+1+IOPTIONMAXLEN+2];
+  FILE *cmo;
+  int l;
+  int admindirlen;
+  char *p;
+  method *meth;
+  option *opt;
+  
+  if (!methoptfile) {
+    admindirlen= strlen(admindir);
+    methoptfile= new char[admindirlen + sizeof(CMETHOPTFILE) + 2];
+    strcpy(methoptfile,admindir);
+    strcpy(methoptfile+admindirlen, "/" CMETHOPTFILE);
+  }
+
+  coption= 0;
+  cmo= fopen(methoptfile,"r");
+  if (!cmo) {
+    if (errno == ENOENT) return;
+    ohshite("unable to open current option file `%.250s'",methoptfile);
+  }
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt open\n");
+  if (!fgets(methoptbuf,sizeof(methoptbuf),cmo)) { fclose(cmo); return; }
+  if (fgetc(cmo) != EOF) { fclose(cmo); return; }
+  if (!feof(cmo)) { fclose(cmo); return; }
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt eof\n");
+  fclose(cmo);
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt read\n");
+  l= strlen(methoptbuf);  if (!l || methoptbuf[l-1] != '\n') return;
+  methoptbuf[--l]= 0;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt len and newline\n");
+  p= strchr(methoptbuf,' ');  if (!p) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt space\n");
+  *p++= 0;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt meth name `%s'\n", methoptbuf);
+  for (meth= methods; meth && strcmp(methoptbuf,meth->name); meth= meth->next);
+  if (!meth) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt meth found; opt `%s'\n",p);
+  for (opt= options; opt && (opt->meth != meth || strcmp(p,opt->name)); opt= opt->next);
+  if (!opt) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt opt found\n");
+  coption= opt;
+}
+
+void writecurrentopt() {
+  FILE *cmo;
+  int l;
+  static char *newfile=0;
+
+  assert(methoptfile);
+  if (!newfile) {
+    l= strlen(methoptfile);
+    newfile= new char[l + sizeof(NEWDBEXT) + 1];
+    strcpy(newfile,methoptfile);
+    strcpy(newfile+l, NEWDBEXT);
+  }
+  cmo= fopen(newfile,"w");
+  if (!cmo) ohshite("unable to open new option file `%.250s'",newfile);
+  if (fprintf(cmo,"%s %s\n",coption->meth->name,coption->name) == EOF) {
+    fclose(cmo);
+    ohshite("unable to write new option to `%.250s'",newfile);
+  }
+  if (fclose(cmo))
+    ohshite("unable to close new option file `%.250s'",newfile);
+  if (rename(newfile,methoptfile))
+    ohshite("unable to install new option as `%.250s'",methoptfile);
+}
diff --git a/dselect/mkcurkeys.pl b/dselect/mkcurkeys.pl
new file mode 100755 (executable)
index 0000000..1929142
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/perl --
+#
+# dselect - Debian GNU/Linux package maintenance user interface
+# mkcurkeys.pl - generate strings mapping key names to ncurses numbers
+#
+# Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+# This 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 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; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@ARGV == 2 || die;
+
+open(OV,"<$ARGV[0]") || die $!;
+while (<OV>) {
+    m/^#/ && next;
+    m/\S/ || next;
+    m/^(\w+)\s+(\S.*\S)\s+$/ || die;
+    $over{$1}= $2;
+    $base{$1}= '';
+}
+close(OV);
+
+for ($i=1, $let='A'; $i<=26; $i++, $let++) {
+    $name{$i}= "^$let";
+    $base{$i}= '';
+}
+
+open(NCH,"<$ARGV[1]") || die $!;
+while (<NCH>) {
+    s/\s+$//;
+    m/#define KEY_(\w+)\s+\d+\s+/ || next;
+    $rhs= $';
+    $k= "KEY_$1";
+    $_= $1;
+    &capit;
+    $base{$k}= $_;
+    $_= $rhs;
+    s/(\w)[\(\)]/$1/g;
+    s/\w+ \((\w+)\)/$1/;
+    next unless m|^/\* (\w[\w ]+\w) \*/$|;
+    $_= $1;
+    s/ key$//;
+    next if s/^shifted /shift / ? m/ .* .* / : m/ .* /;
+    &capit;
+    $name{$k}= $_;
+}
+close(NCH);
+
+printf(<<'END') || die $!;
+/*
+ * WARNING - THIS FILE IS GENERATED AUTOMATICALLY - DO NOT EDIT
+ * It is generated by mkcurkeys.pl from <ncurses/curses.h>
+ * and keyoverride.  If you want to override things try adding
+ * them to keyoverride.
+ */
+
+END
+
+for ($i=33; $i<=126; $i++) {
+    $k= $i;
+    $v= pack("C",$i);
+    if ($v eq ',') { $comma=$k; next; }
+    &p;
+}
+
+for $k (sort {
+    $a+0 eq $a ?
+        $b+0 eq $b ? $a <=> $b : -1
+            : $b+0 eq $b ? 1 :
+                $a cmp $b
+                } keys %base) {
+    $v= $base{$k};
+    $v= $name{$k} if defined($name{$k});
+    $v= $over{$k} if defined($over{$k});
+    next if $v eq '[elide]';
+    &p;
+}
+
+for ($i=1; $i<64; $i++) {
+    $k= "KEY_F($i)"; $v= "F$i";
+    &p;
+}
+
+$k=$comma; $v=','; &p;
+
+print(<<'END') || die $!;
+  { -1,              0                    }
+END
+
+close(STDOUT) || die $!;
+exit(0);
+
+sub capit {
+    $o= ''; y/A-Z/a-z/; $_= " $_";
+    while (m/ (\w)/) {
+        $o .= $`.' ';
+        $_ = $1;
+        y/a-z/A-Z/;
+        $o .= $_;
+        $_ = $';
+    }
+    $_= $o.$_; s/^ //;
+}
+
+sub p {
+    $v =~ s/["\\]/\\$&/g;
+    printf("  { %-15s \"%-20s },\n",
+           $k.',',
+           $v.'"') || die $!;
+}
diff --git a/dselect/mkhelpmsgs.pl b/dselect/mkhelpmsgs.pl
new file mode 100755 (executable)
index 0000000..878620f
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+
+$maxnlines= 22;
+
+open(SRC,"helpmsgs.src") || die $!;
+open(NC,">helpmsgs.cc.new") || die $!;
+open(NH,">helpmsgs.h.new") || die $!;
+
+&autowarn('NC'); &autowarn('NH');
+
+print(NC "#include \"helpmsgs.h\"\n") || die $!;
+print(NH <<'END') || die $!;
+#ifndef HELPMSGS_H
+#define HELPMSGS_H
+struct helpmessage { const char *title; const char *text; };
+END
+
+$state= 'start';
+$nblanks= 0; $nlines= 0;
+while (<SRC>) {
+    s/\"/\\\"/g;
+    if (m/^\@\@\@ (\w+)\s+(\S.*\S)\s+$/) {
+        &finishif;
+        $currentname= $1; $currenttitle= $2;
+        print(NH "extern const struct helpmessage hlp_$currentname;\n") || die $!;
+        print(NC
+              "const struct helpmessage hlp_$currentname = {\n".
+              "  \"$currenttitle\", \"") || die $!;
+    } elsif (m/^\@\@\@/) {
+        die;
+    } elsif (!m/\S/) {
+        $nblanks++;
+    } else {
+        if ($state ne 'start' && $nblanks) {
+            print(NC ("\\n"x$nblanks)."\\\n") || die $!;
+            $nlines+= $nblanks;
+        }
+        $state= 'middle'; $nblanks= 0;
+        s/\s*\n$//;
+        print(NC "\\\n".$_."\\n") || die $!;
+        $nlines++;
+    }
+}
+
+&finishif;
+
+close(NC) || die $!;
+print(NH "#endif /* HELPMSGS_H */\n") || die $!;
+close(NH) || die $!;
+
+rename("helpmsgs.cc.new","helpmsgs.cc") || die $!;
+rename("helpmsgs.h.new","helpmsgs.h") || die $!;
+    
+sub finishif {
+    if ($state ne 'start') {
+        print(NC "\"\n};\n") || die $!;
+        printf "\t\t%s: %d lines\n",$currentname,$nlines;
+        if ($nlines > $maxnlines) { warn "Too many lines in $currentname"; }
+    }
+    $state= 'start';
+    $nblanks= 0; $nlines= 0;
+}
+
+
+sub autowarn {
+    $fh= $_[0];
+    print($fh <<'END') || die $!;
+/*
+ * WARNING - THIS FILE IS GENERATED AUTOMATICALLY - DO NOT EDIT
+ * It is generated by mkhelpmsgs.pl from helpmsgs.src.
+ */
+
+END
+}
diff --git a/dselect/pkgcmds.cc b/dselect/pkgcmds.cc
new file mode 100644 (file)
index 0000000..bc728af
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgcmds.cc - package list keyboard commands
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+static int matches(struct pkginfo *pkg, struct pkginfo *comparewith) {
+  if (comparewith->priority != pkginfo::pri_unset &&
+      (comparewith->priority != pkg->priority ||
+       comparewith->priority == pkginfo::pri_other &&
+       strcasecmp(comparewith->otherpriority,pkg->otherpriority)))
+    return 0;
+  if (comparewith->section &&
+      strcasecmp(comparewith->section,
+                 pkg->section ?
+                 pkg->section : ""))
+    return 0;
+  return 1;
+}
+
+void packagelist::affectedrange(int *startp, int *endp) {
+  if (table[cursorline]->pkg->name) {
+    *startp= cursorline;
+    *endp= cursorline+1;
+    return;
+  }
+  int index;
+  for (index= cursorline; index < nitems && !table[index]->pkg->name; index++);
+  if (index >= nitems) {
+    *startp= *endp= cursorline;
+    return;
+  }
+  *startp= index;
+  while (index < nitems && matches(table[index]->pkg,table[cursorline]->pkg)) index++;
+  *endp= index;
+}
+
+void packagelist::movecursorafter(int ncursor) {
+  if (ncursor >= nitems) ncursor= nitems-1;
+  topofscreen += ncursor-cursorline;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setcursor(ncursor);
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::setwant(pkginfo::pkgwant nw) {
+  int index, top, bot;
+
+  if (!readwrite) { beep(); return; }
+
+  if (recursive) {
+    redrawitemsrange(cursorline,cursorline+1);
+    table[cursorline]->selected= nw;
+    redraw1item(cursorline);
+    top= cursorline;
+    bot= cursorline+1;
+  } else {
+    packagelist *sub= new packagelist(bindings,0);
+
+    affectedrange(&top,&bot);
+    for (index= top; index < bot; index++) {
+      if (!table[index]->pkg->name ||
+          table[index]->selected == nw ||
+          table[index]->selected == pkginfo::want_purge && nw == pkginfo::want_deinstall)
+        continue;
+      sub->add(table[index]->pkg,nw);
+    }
+
+    repeatedlydisplay(sub,dp_may,this);
+    for (index=top; index < bot; index++)
+      redraw1item(index);
+  }
+  movecursorafter(bot);
+}
+
+void packagelist::kd_select()   { setwant(pkginfo::want_install);   }
+void packagelist::kd_deselect() { setwant(pkginfo::want_deinstall); }
+void packagelist::kd_purge()    { setwant(pkginfo::want_purge);     }
+
+void packagelist::sethold(int hold) {
+  int top, bot, index;
+
+  if (!readwrite) { beep(); return; }
+
+  affectedrange(&top,&bot);
+  for (index= top; index < bot; index++) {
+    // Sorry about the contortions, but GCC produces a silly warning otherwise
+    unsigned int neweflag= table[index]->pkg->eflag;
+    if (hold) neweflag |= pkginfo::eflagf_hold;
+    else neweflag &= ~pkginfo::eflagf_hold;
+    table[index]->pkg->eflag= (enum pkginfo::pkgeflag)neweflag;
+    redraw1item(index);
+  }
+  movecursorafter(bot);
+}
+
+void packagelist::kd_hold()     { sethold(1);                       }
+void packagelist::kd_unhold()   { sethold(0);                       }
+
+const char *packagelist::itemname(int index) {
+  return table[index]->pkg->name;
+}
+
+void packagelist::kd_swaporder() {
+  switch (sortorder) {
+  case so_priority:  sortorder= so_section;   break;
+  case so_section:   sortorder= so_alpha;     break;
+  case so_alpha:     sortorder= so_priority;  break;
+  case so_unsorted:                           return;
+  default: internerr("unknown sort in kd_swaporder");
+  }
+  const char *oldname= table[cursorline]->pkg->name;
+  sortmakeheads();
+  int newcursor;
+  newcursor= 0;
+  if (oldname) {
+    int index;
+    for (index=0; index<nitems; index++) {
+      if (table[index]->pkg->name && !strcasecmp(oldname,table[index]->pkg->name)) {
+        newcursor= index;
+        break;
+      }
+    }
+  }
+  topofscreen= newcursor-1;
+  if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setwidths();
+  redrawtitle();
+  redrawcolheads();
+  ldrawnstart= ldrawnend= -1;
+  cursorline= -1;
+  setcursor(newcursor);
+  refreshlist();
+}
+
+void packagelist::kd_verbose() {
+  verbose= !verbose;
+  setwidths();
+  leftofscreen= 0;
+  ldrawnstart= ldrawnend= -1;
+  redrawtitle();
+  redrawcolheads();
+  redrawitemsrange(topofscreen,lesserint(topofscreen+list_height,nitems));
+  refreshlist();
+}
+
+void packagelist::kd_quit_noop() { }
+
+void packagelist::kd_revert_abort() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->original;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::kd_revertdirect() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->direct;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::kd_revertsuggest() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->suggested;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+/* fixme: configurable purge/deselect */
+/* fixme: un-hold things */
+
+void packagelist::kd_info() {
+  currentinfo++;
+  infotopofscreen=0;
+  redrawinfo();
+}
diff --git a/dselect/pkgdepcon.cc b/dselect/pkgdepcon.cc
new file mode 100644 (file)
index 0000000..6026a5d
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgdepcon.cc - dependency and conflict resolution
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+static const int depdebug= 1;
+
+int packagelist::resolvesuggest() {
+  // We continually go around looking for things to change, but we may
+  // only change the `suggested' value if we also increase the `priority'
+  // Return 2 if we made a change due to a Recommended, Depends or Conficts,
+  // or 1 if we offered or made a change because of an Optional line.
+  if (debug)
+    fprintf(debug,"packagelist[%p]::resolvesuggest()\n",this);
+  int changemade, maxchangemade;
+  maxchangemade= 0;
+  for (;;) {
+    changemade= 0;
+    int index;
+    for (index=0; index<nitems; index++) {
+      if (!table[index]->pkg->name) continue;
+      if (depdebug)
+        fprintf(debug,"packagelist[%p]::resolvesuggest() loop[%i] %s / %d\n",
+                this, index, table[index]->pkg->name, changemade);
+      dependency *depends;
+      for (depends= table[index]->pkg->available.depends;
+           depends;
+           depends= depends->next)
+        changemade= greaterint(changemade, resolvedepcon(depends));
+      deppossi *possi;
+      for (possi= table[index]->pkg->available.depended;
+           possi;
+           possi= possi->nextrev) 
+        changemade= greaterint(changemade, resolvedepcon(possi->up));
+      for (depends= table[index]->pkg->available.depends;
+           depends;
+           depends= depends->next)
+        if (depends->type == dep_provides)
+          for (possi= depends->list->ed->available.valid
+                      ? depends->list->ed->available.depended : 0;
+               possi;
+               possi= possi->nextrev)
+            changemade= greaterint(changemade, resolvedepcon(possi->up));
+      if (depdebug)
+        fprintf(debug,"packagelist[%p]::resolvesuggest() loop[%i] %s / -> %d\n",
+                this, index, table[index]->pkg->name, changemade);
+    }
+    if (!changemade) break;
+    maxchangemade= greaterint(maxchangemade, changemade);
+  }
+  if (debug)
+    fprintf(debug,"packagelist[%p]::resolvesuggest() done; maxchangemade=%d\n",
+            this,maxchangemade);
+  return maxchangemade;
+}
+
+static int dep_update_best_to_change_stop(perpackagestate *& best, pkginfo *trythis) {
+  // There's no point trying to select a pure virtual package.
+  if (!trythis->clientdata) return 0;
+  
+  if (depdebug)
+    fprintf(debug,"update_best_to_change(best=%s{%d}, test=%s{%d});\n",
+            best ? best->pkg->name : "", best ? (int)best->spriority : -1,
+            trythis->name, trythis->clientdata->spriority);
+
+  // If the problem is caused by us deselecting one of these packages
+  // we should not try to select another one instead.
+  if (trythis->clientdata->spriority == sp_deselecting) return 1;
+
+  // If we haven't found anything yet then this is our best so far.
+  if (!best) goto yes;
+  
+  // Select the package with the lowest priority (ie, the one of whom
+  // we were least sure we wanted it deselected).
+  if (trythis->clientdata->spriority > best->spriority) return 0;
+  if (trythis->clientdata->spriority < best->spriority) goto yes;
+
+  // Pick the package with the must fundamental recommendation level.
+  if (trythis->priority > best->pkg->priority) return 0;
+  if (trythis->priority < best->pkg->priority) goto yes;
+
+  // If we're still unsure we'll change the first one in the list.
+  return 0;
+  
+ yes:
+  if (depdebug) fprintf(debug,"update_best_to_change(); yes\n");
+
+  best=trythis->clientdata; return 0;
+}
+
+int packagelist::deselect_one_of(pkginfo *per, pkginfo *ped, dependency *display) {
+  perpackagestate *er= per->clientdata;
+  perpackagestate *ed= ped->clientdata;
+  
+  if (!er || er->selected != pkginfo::want_install ||
+      !ed || ed->selected != pkginfo::want_install) return 0;
+  
+  add(display,dp_must);
+  
+  er= per->clientdata;  // these can be changed by add
+  ed= ped->clientdata;
+  
+  if (depdebug)
+    fprintf(debug,"packagelist[%p]::deselect_one_of(): er %s{%d} ed %s{%d} [%p]\n",
+            this, er->pkg->name, er->spriority, ed->pkg->name, ed->spriority, display);
+  
+  perpackagestate *best;
+  if (er->spriority < ed->spriority) best= er;        // We'd rather change the
+  else if (er->spriority > ed->spriority) best= ed;   // one with the lowest priority.
+  
+  else if (er->pkg->priority >
+           er->pkg->priority) best= er;         // ... failing that the one with
+  else if (er->pkg->priority <                  //  the highest priority
+           er->pkg->priority) best= ed;
+  
+  else best= ed;                                      // ... failing that, the second
+
+  if (depdebug)
+    fprintf(debug,"packagelist[%p]::deselect_one_of(): best %s{%d}\n",
+            this, best->pkg->name, best->spriority);
+
+  if (best->spriority >= sp_deselecting) return 0;
+  best->suggested=
+    best->pkg->status == pkginfo::stat_notinstalled
+      ? pkginfo::want_purge : pkginfo::want_deinstall; /* fixme: configurable */
+  best->selected= best->suggested;
+  best->spriority= sp_deselecting;
+
+  return 2;
+}
+
+int packagelist::resolvedepcon(dependency *depends) {
+  perpackagestate *best;
+  deppossi *possi, *provider;
+  int r, foundany;
+
+  if (depdebug) {
+    fprintf(debug,"packagelist[%p]::resolvedepcon([%p] %s --%s-->",
+            this,depends,depends->up->name,relatestrings[depends->type]);
+    for (possi=depends->list; possi; possi=possi->next)
+      fprintf(debug," %s",possi->ed->name);
+    fprintf(debug,"); (ing)->want=%s\n",
+            depends->up->clientdata
+            ? wantstrings[depends->up->clientdata->suggested]
+            : "(no clientdata)");
+  }
+  
+  if (!depends->up->clientdata) return 0;
+  
+  if (depends->up->clientdata->selected != pkginfo::want_install) return 0;
+
+  switch (depends->type) {
+
+  case dep_provides:
+  case dep_replaces:
+    return 0;
+    
+  case dep_suggests:
+    if (0) return 0; /* fixme: configurable */
+    // fall through ...
+  case dep_recommends:
+  case dep_depends:
+  case dep_predepends:
+    for (possi= depends->list;
+         possi && !deppossatisfied(possi);
+         possi= possi->next);
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): depends found %s\n",
+              this,depends, possi ? possi->ed->name : "[none]");
+    if (possi) return 0;
+
+    // Ensures all in the recursive list; adds info strings; ups priorities
+    r= add(depends, depends->type == dep_suggests ? dp_may : dp_must);
+
+    if (depends->type == dep_suggests) return r;
+
+    best= 0;
+    for (possi= depends->list;
+         possi;
+         possi= possi->next) {
+      foundany= 0;
+      if (possi->ed->clientdata) foundany= 1;
+      if (dep_update_best_to_change_stop(best, possi->ed)) goto mustdeselect;
+      for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+           provider;
+           provider= provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+        if (provider->up->up->clientdata) foundany= 1;
+        if (dep_update_best_to_change_stop(best, provider->up->up)) goto mustdeselect;
+      }
+      if (!foundany) addunavailable(possi);
+    }
+
+    if (!best) {
+      if (depdebug) fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): "
+                            "mustdeselect nobest\n", this,depends);
+      return r;
+    }
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): select best=%s{%d}\n",
+              this,depends, best->pkg->name, best->spriority);
+    if (best->spriority >= sp_selecting) return r;
+    best->selected= best->suggested= pkginfo::want_install;
+    best->spriority= sp_selecting;
+    return 2;
+    
+  mustdeselect:
+    best= depends->up->clientdata;
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): mustdeselect best=%s{%d}\n",
+              this,depends, best->pkg->name, best->spriority);
+
+    if (best->spriority >= sp_deselecting) return r;
+    best->selected= best->suggested=
+      best->pkg->status == pkginfo::stat_notinstalled
+        ? pkginfo::want_purge : pkginfo::want_deinstall; /* fixme: configurable */
+    best->spriority= sp_deselecting;
+    return 2;
+    
+  case dep_conflicts:
+    if (!deppossatisfied(depends->list)) return 0;
+    if (depends->up != depends->list->ed) {
+      r= deselect_one_of(depends->up, depends->list->ed, depends);  if (r) return r;
+    }
+    for (provider= depends->list->ed->available.valid ?
+                   depends->list->ed->available.depended : 0;
+         provider;
+         provider= provider->nextrev) {
+      if (provider->up->type != dep_provides) continue;
+      if (provider->up->up == depends->up) continue; // conflicts & provides same thing
+      r= deselect_one_of(depends->up, provider->up->up, depends);  if (r) return r;
+    }
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): no desel\n", this,depends);
+    return 0;
+    
+  default:
+    internerr("unknown deptype");
+  }
+}
+
+int deppossatisfied(deppossi *possi) {
+  if (possi->ed->clientdata &&
+      possi->ed->clientdata->selected == pkginfo::want_install &&
+      !(possi->up->type == dep_conflicts && possi->up->up == possi->ed)) {
+    // If it's installed, then either it's of the right version,
+    // and therefore OK, or a version must have been specified,
+    // in which case we don't need to look at the rest anyway.
+    if (possi->verrel == deppossi::dvr_none) return 1;
+    int r= versioncompare(possi->ed->available.version,
+                          possi->ed->available.revision,
+                          possi->version,
+                          possi->revision);
+    switch (possi->verrel) {
+    case deppossi::dvr_earlierequal:   return r <= 0;
+    case deppossi::dvr_laterequal:     return r >= 0;
+    case deppossi::dvr_earlierstrict:  return r < 0;
+    case deppossi::dvr_laterstrict:    return r > 0;
+    case deppossi::dvr_exact:          return r == 0;
+    default:                           internerr("unknown verrel");
+    }
+  }
+  if (possi->verrel != deppossi::dvr_none) return 0;
+  deppossi *provider;
+  for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+       provider;
+       provider= provider->nextrev) {
+    if (provider->up->type != dep_provides) continue;
+    if (provider->up->up->clientdata &&
+        provider->up->up->clientdata->selected == pkginfo::want_install)
+      return 1;
+  }
+  return 0;
+}
diff --git a/dselect/pkgdisplay.cc b/dselect/pkgdisplay.cc
new file mode 100644 (file)
index 0000000..4704e21
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgdisplay.cc - package list display
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+/* These MUST be in the same order as the corresponding enums in dpkg-db.h */
+const char
+  *const wantstrings[]=   { "new package", "selected", "deselected", "purge", 0 },
+  *const holdstrings[]=   { "", "on hold", "REINSTALL",
+                            "hold,REINSTALL", 0 },
+  *const statusstrings[]= { "not installed", "unpacked (not set up)",
+                            "failed config", "installed", "half installed",
+                            "removed (configs remain)", 0                            },
+  *const prioritystrings[]=  { "Required", "Important", "Standard", "Recommended",
+                               "Optional", "Extra", "Contrib",
+                               "!Bug!", "Unclassified", 0                          },
+  *const relatestrings[]= { "suggests", "recommends", "depends on", "pre-depends on",
+                            "conflicts with", "provides", 0              },
+  *const priorityabbrevs[]=  { "Req", "Imp", "Std", "Rec",
+                               "Opt", "Xtr", "Ctb",
+                               "bUG", "?"                  };
+const char statuschars[]=   " uF*H-";
+const char holdchars[]=     " hRX";
+const char wantchars[]=     "n*-_";
+
+static int maximumstring(const char *const *array) {
+  int maxlen= 0;
+  while (*array) {
+    int l= strlen(*array);
+    const char *p= strchr(*array, '(');
+    if (p && p > *array && *--p == ' ') l= p - *array;
+    if (l > maxlen) maxlen= l;
+    array++;
+  }
+  return maxlen;
+}
+
+void packagelist::setwidths() {
+  if (debug) fprintf(debug,"packagelist[%p]::setwidths()\n",this);
+
+  if (verbose) {
+    status_hold_width= 9;
+    status_status_width= maximumstring(statusstrings);
+    status_want_width= maximumstring(wantstrings);
+    status_width= status_hold_width+status_status_width+status_want_width*2+3;
+    priority_width= 8;
+   package_width= 16;
+  } else {
+    status_width= 4;
+    priority_width= 3;
+    package_width= 12;
+  }
+  section_width= 8;
+
+  gap_width= 1;
+
+  if (sortorder == so_section) {
+    section_column= status_width + gap_width;
+    priority_column= section_column + section_width + gap_width;
+    package_column= priority_column + priority_width + gap_width;
+  } else {
+    priority_column= status_width + gap_width;
+    section_column= priority_column + priority_width + gap_width;
+    package_column= section_column + section_width + gap_width;
+  }
+
+  description_column= package_column + package_width + gap_width;
+
+  total_width= TOTAL_LIST_WIDTH;
+  description_width= total_width - description_column;
+}
+
+void packagelist::redrawtitle() {
+  int x,y;
+  
+  if (title_height) {
+    mywerase(titlewin);
+    mvwaddnstr(titlewin,0,0,
+               recursive ?  "dselect - recursive package listing" :
+               !readwrite ? "dselect - inspection of package states" :
+                            "dselect - main package listing",
+               xmax);
+    getyx(titlewin,y,x);
+    if (x < xmax) {
+      switch (sortorder) {
+      case so_section:
+        waddnstr(titlewin, " (by section)", xmax-x);
+        break;
+      case so_priority:
+        waddnstr(titlewin, " (by priority)", xmax-x);
+        break;
+      case so_alpha:
+        waddnstr(titlewin, " (alphabetically)", xmax-x);
+        break;
+      case so_unsorted:
+        break;
+      default:
+        internerr("bad sort in redrawtitle");
+      }
+    }
+    const char *helpstring= readwrite ? (verbose ? " +/-=select v=terse ?=help"
+                                                 : " +/-=select v=verbose ?=help")
+                                      : (verbose ? " v=terse ?=help"
+                                                 : " v=verbose ?=help");
+    int l= strlen(helpstring);
+    getyx(titlewin,y,x);
+    if (xmax-l > 0) {
+      mvwaddstr(titlewin,0,xmax-l, helpstring);
+    }
+    wnoutrefresh(titlewin);
+  }
+}
diff --git a/dselect/pkginfo.cc b/dselect/pkginfo.cc
new file mode 100644 (file)
index 0000000..69b0df9
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkginfo.cc - handles (re)draw of package list window infopad
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "helpmsgs.h"
+
+const struct helpmenuentry *packagelist::helpmenulist() {
+  static const struct helpmenuentry
+    rw[]= {
+      { 'i', &hlp_mainintro       },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    },
+    ro[]= {
+      { 'i', &hlp_readonlyintro   },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    },
+    recur[]= {
+      { 'i', &hlp_recurintro      },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    };
+  return
+    !readwrite ? ro :
+    !recursive ? rw :
+                 recur;
+}
+
+int packagelist::itr_recursive() { return recursive; }
+
+const packagelist::infotype packagelist::infoinfos[]= {
+  { itr_recursive,     itd_relations    },
+  { 0,                 itd_description  },
+  { 0,                 itd_controlfile  },
+  { 0,                 0                }
+};
+
+const packagelist::infotype *const packagelist::baseinfo= infoinfos;
+
+void packagelist::severalinfoblurb(const char *whatinfoline) {
+  whatinfovb(whatinfoline);
+  varbuf vb;
+  vb("The line you have highlighted represents many packages; "
+     "if you ask to select or deselect it you will affect all the "
+     "packages which match the criterion shown.\n"
+     "\n"
+     "If you move the highlight to a line for a particular package "
+     "you will see information about that package displayed here.");
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_relations() {
+  if (table[cursorline]->pkg->name) {
+    whatinfovb("interrelationships affecting ");
+    whatinfovb(table[cursorline]->pkg->name);
+    if (debug) fprintf(debug,"packagelist[%p]::idt_relations(); `%s'\n",
+                       this,table[cursorline]->relations.string());
+    waddstr(infopad,table[cursorline]->relations.string());
+  } else {
+    severalinfoblurb("interrelationships");
+  }
+}
+
+void packagelist::itd_description() {
+  if (table[cursorline]->pkg->name) {
+    whatinfovb("description of ");
+    whatinfovb(table[cursorline]->pkg->name);
+
+    const char *m= table[cursorline]->pkg->available.description;
+    if (!m || !*m) m= "no description available.";
+    const char *p= strchr(m,'\n');
+    int l= p ? (int)(p-m) : strlen(m);
+    wattrset(infopad,info_headattr);
+    waddstr(infopad, table[cursorline]->pkg->name);
+    waddstr(infopad," - ");
+    waddnstr(infopad,m,l);
+    wattrset(infopad,info_attr);
+    if (p) {
+      waddstr(infopad,"\n\n");
+      wordwrapinfo(1,++p);
+    }
+  } else {
+    severalinfoblurb("description");
+  }
+}
+
+void packagelist::itd_controlfile() {
+  werase(infopad);
+  if (!table[cursorline]->pkg->name) {
+    severalinfoblurb("control file information");
+  } else {
+    whatinfovb("control file information for ");
+    whatinfovb(table[cursorline]->pkg->name);
+    varbuf vb;
+    varbufrecord(&vb,table[cursorline]->pkg,&table[cursorline]->pkg->available);
+    vb.terminate();
+    if (debug)
+      fprintf(debug,"packagelist[%p]::idt_controlfile(); `%s'\n",this,vb.string());
+    waddstr(infopad,vb.string());
+  }
+}
+
+void packagelist::redrawinfo() {
+  for (;;) {
+    if (!currentinfo || !currentinfo->display) currentinfo= baseinfo;
+    if (!currentinfo->relevant) break;
+    if ((this->*currentinfo->relevant)()) break;
+    currentinfo++;
+  }
+  if (!info_height) return;
+  whatinfovb.reset();
+  werase(infopad); wmove(infopad,0,0);
+  
+  if (debug)
+    fprintf(debug,"packagelist[%p]::redrawinfo(); #=%d\n", this,
+            (int)(currentinfo - baseinfo));
+  
+  (this->*currentinfo->display)();
+  whatinfovb.terminate();
+  int y,x;
+  getyx(infopad, y,x);
+  if (x) y++;
+  infolines= y;
+
+  refreshinfo();
+}
diff --git a/dselect/pkgkeys.cc b/dselect/pkgkeys.cc
new file mode 100644 (file)
index 0000000..5e47a93
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgkeys.cc - package list keybindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::interpretation packagelist_kinterps[] = {
+  { "up",             0,  packagelist::kd_up,               qa_noquit           },
+  { "down",           0,  packagelist::kd_down,             qa_noquit           },
+  { "top",            0,  packagelist::kd_top,              qa_noquit           },
+  { "bottom",         0,  packagelist::kd_bottom,           qa_noquit           },
+  { "scrollon",       0,  packagelist::kd_scrollon,         qa_noquit           },
+  { "scrollback",     0,  packagelist::kd_scrollback,       qa_noquit           },
+  { "iscrollon",      0,  packagelist::kd_iscrollon,        qa_noquit           },
+  { "iscrollback",    0,  packagelist::kd_iscrollback,      qa_noquit           },
+  { "scrollon1",      0,  packagelist::kd_scrollon1,        qa_noquit           },
+  { "scrollback1",    0,  packagelist::kd_scrollback1,      qa_noquit           },
+  { "iscrollon1",     0,  packagelist::kd_iscrollon1,       qa_noquit           },
+  { "iscrollback1",   0,  packagelist::kd_iscrollback1,     qa_noquit           },
+  { "panon",          0,  packagelist::kd_panon,            qa_noquit           },
+  { "panback",        0,  packagelist::kd_panback,          qa_noquit           },
+  { "panon1",         0,  packagelist::kd_panon1,           qa_noquit           },
+  { "panback1",       0,  packagelist::kd_panback1,         qa_noquit           },
+  { "select",         0,  packagelist::kd_select,           qa_noquit           },
+  { "deselect",       0,  packagelist::kd_deselect,         qa_noquit           },
+  { "purge",          0,  packagelist::kd_purge,            qa_noquit           },
+  { "hold",           0,  packagelist::kd_hold,             qa_noquit           },
+  { "unhold",         0,  packagelist::kd_unhold,           qa_noquit           },
+  { "info",           0,  packagelist::kd_info,             qa_noquit           },
+  { "verbose",        0,  packagelist::kd_verbose,          qa_noquit           },
+  { "help",           0,  packagelist::kd_help,             qa_noquit           },
+  { "search",         0,  packagelist::kd_search,           qa_noquit           },
+  { "searchagain",    0,  packagelist::kd_searchagain,      qa_noquit           },
+  { "swaporder",      0,  packagelist::kd_swaporder,        qa_noquit           },
+  { "redraw",         0,  packagelist::kd_redraw,           qa_noquit           },
+  { "quitcheck",      0,  packagelist::kd_quit_noop,        qa_quitchecksave    },
+  { "quitrejectsug",  0,  packagelist::kd_revertdirect,     qa_quitnochecksave  },
+  { "quitnocheck",    0,  packagelist::kd_quit_noop,        qa_quitnochecksave  },
+  { "abortnocheck",   0,  packagelist::kd_revert_abort,     qa_quitnochecksave  },
+  { "revert",         0,  packagelist::kd_revert_abort,     qa_noquit           },
+  { "revertsuggest",  0,  packagelist::kd_revertsuggest,    qa_noquit           },
+  { "revertdirect",   0,  packagelist::kd_revertdirect,     qa_noquit           },
+  {  0,               0,                                    qa_noquit           }
+};
+
+#define C(x) ((x)-'a'+1)
+
+const keybindings::orgbinding packagelist_korgbindings[]= {
+  { 'n',            "down"           },
+  { KEY_DOWN,       "down"           },
+  { 'p',            "up"             },
+  { KEY_UP,         "up"             },
+  
+  { 'N',            "scrollon"       },
+  { KEY_NPAGE,      "scrollon"       },
+  { ' ',            "scrollon"       },
+  { 'P',            "scrollback"     },
+  { KEY_PPAGE,      "scrollback"     },
+  { KEY_BACKSPACE,  "scrollback"     },
+  { 0177,/*DEL*/    "scrollback"     },
+  { C('h'),         "scrollback"     },
+  { C('n'),         "scrollon1"      },
+  { C('p'),         "scrollback1"    },
+  
+  { 't',            "top"            },
+  { KEY_HOME,       "top"            },
+  { 'e',            "bottom"         },
+  { KEY_LL,         "bottom"         },
+  { KEY_END,        "bottom"         },
+  
+  { 'u',            "iscrollback"    },
+  { 'd',            "iscrollon"      },
+  { C('u'),         "iscrollback1"   },
+  { C('d'),         "iscrollon1"     },
+  
+  { 'B',            "panback"        },
+  { KEY_LEFT,       "panback"        },
+  { 'F',            "panon"          },
+  { KEY_RIGHT,      "panon"          },
+  { C('b'),         "panback1"       },
+  { C('f'),         "panon1"         },
+
+  { '+',            "select"         },
+  { KEY_IC,         "select"         },
+  { '-',            "deselect"       },
+  { KEY_DC,         "deselect"       },
+  { '_',            "purge"          },
+  { 'H',            "hold"           },
+  { 'G',            "unhold"         },
+  
+  { '?',            "help"           },
+  { KEY_HELP,       "help"           },
+  { KEY_F(1),       "help"           },
+  { 'i',            "info"           },
+  { 'o',            "swaporder"      },
+  { 'v',            "verbose"        },
+  { C('l'),         "redraw"         },
+  { '/',            "search"         },
+  { '\\',           "searchagain"    },
+
+  { KEY_ENTER,      "quitcheck"      },
+  { '\r',           "quitcheck"      },
+  { 'Q',            "quitnocheck"    },
+  { 'X',            "abortnocheck"   },
+  { 'R',            "revert"         },
+  { 'U',            "revertsuggest"  },
+  { 'D',            "revertdirect"   },
+
+  {  -1,             0               }
+};
diff --git a/dselect/pkglist.cc b/dselect/pkglist.cc
new file mode 100644 (file)
index 0000000..f619a75
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkglist.cc - package list administration
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+int packagelist::compareentries(struct perpackagestate *a,
+                                struct perpackagestate *b) {
+  const char *asection= a->pkg->section;
+  if (!asection && a->pkg->name) asection= "";
+  const char *bsection= b->pkg->section;
+  if (!bsection && b->pkg->name) bsection= "";
+  int c_section=
+    !asection || !bsection ?
+      (!bsection) - (!asection) :
+    !*asection || !*bsection ?
+      (!asection) - (!bsection) :
+    strcasecmp(asection,bsection);
+  int c_priority=
+    a->pkg->priority - b->pkg->priority;
+  if (!c_priority && a->pkg->priority == pkginfo::pri_other)
+    c_priority= strcasecmp(a->pkg->otherpriority, b->pkg->otherpriority);
+  int c_name=
+    a->pkg->name && b->pkg->name ?
+      strcasecmp(a->pkg->name, b->pkg->name) :
+    (!b->pkg->name) - (!a->pkg->name);
+
+  switch (sortorder) {
+  case so_section:
+    return c_section ? c_section : c_priority ? c_priority : c_name;
+  case so_priority:
+    return c_priority ? c_priority : c_section ? c_section : c_name;
+  case so_alpha:
+    return c_name;
+  case so_unsorted:
+  default:
+    internerr("unsorted or unknown in compareentries");
+  }
+}
+
+void packagelist::discardheadings() {
+  int a,b;
+  for (a=0, b=0; a<nitems; a++) {
+    if (table[a]->pkg->name) {
+      table[b++]= table[a];
+    }
+  }
+  nitems= b;
+
+  struct perpackagestate *head, *next;
+  head= headings;
+  while (head) {
+    next= head->uprec;
+    delete head->pkg;
+    delete head;
+    head= next;
+  }
+  headings= 0;
+}
+
+void packagelist::addheading(pkginfo::pkgpriority priority,
+                             const char *otherpriority,
+                             const char *section) {
+  assert(nitems <= nallocated);
+  if (nitems == nallocated) {
+    nallocated += nallocated+50;
+    struct perpackagestate **newtable= new struct perpackagestate*[nallocated];
+    memcpy(newtable,table,nallocated*sizeof(struct perpackagestate*));
+    table= newtable;
+  }
+  
+  if (debug) fprintf(debug,"packagelist[%p]::addheading(%d,%s,%s)\n",
+                     this,priority,
+                     otherpriority ? otherpriority : "<null>",
+                     section ? section : "<null>");
+
+  struct pkginfo *newhead= new pkginfo;
+  newhead->name= 0;
+  newhead->priority= priority;
+  newhead->otherpriority= (char*)otherpriority;
+  newhead->section= (char*)section;
+
+  struct perpackagestate *newstate= new perpackagestate;
+  newstate->pkg= newhead;
+  newstate->uprec= headings;
+  headings= newstate;
+  table[nitems++]= newstate;
+}
+
+static packagelist *sortpackagelist;
+
+int qsort_compareentries(const void *a, const void *b) {
+  return sortpackagelist->compareentries(*(perpackagestate**)a,
+                                         *(perpackagestate**)b);
+}
+
+void packagelist::sortinplace() {
+  sortpackagelist= this;
+
+  if (debug) fprintf(debug,"packagelist[%p]::sortinplace()\n",this);
+  qsort(table,nitems,sizeof(struct pkginfoperfile*),qsort_compareentries);
+}
+
+void packagelist::sortmakeheads() {
+  discardheadings();
+  sortinplace();
+  assert(nitems);
+
+  if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads() sortorder=%d\n",
+                     this,sortorder);
+  
+  int nrealitems= nitems;
+  addheading(pkginfo::pri_unset,0,0);
+
+  if (sortorder == so_alpha) { sortinplace(); return; }
+  
+  assert(sortorder == so_section || sortorder == so_priority);
+
+  // Important: do not save pointers into table in this function, because
+  // addheading may need to reallocate table to make it larger !
+  
+  struct pkginfo *lastpkg;
+  struct pkginfo *thispkg;
+  lastpkg= 0;
+  int a;
+  for (a=0; a<nrealitems; a++) {
+    thispkg= table[a]->pkg;
+    assert(thispkg->name);
+    int prioritydiff= (!lastpkg ||
+                       thispkg->priority != lastpkg->priority ||
+                       (thispkg->priority == pkginfo::pri_other &&
+                        strcasecmp(thispkg->otherpriority,lastpkg->otherpriority)));
+    int sectiondiff= (!lastpkg ||
+                      strcasecmp(thispkg->section ? thispkg->section : "",
+                                 lastpkg->section ? lastpkg->section : ""));
+
+    if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads()"
+                       " pkg=%s  priority=%d otherpriority=%s %s  section=%s %s\n",
+                       this, thispkg->name, thispkg->priority,
+                       thispkg->otherpriority ? thispkg->otherpriority : "<null>",
+                       prioritydiff ? "*diff*" : "same",
+                       thispkg->section ? thispkg->section : "<null>",
+                       sectiondiff ? "*diff*" : "same");
+
+    if (sortorder == so_section && sectiondiff)
+      addheading(pkginfo::pri_unset,0, thispkg->section ? thispkg->section : "");
+    if (sortorder == so_priority && prioritydiff)
+      addheading(thispkg->priority,thispkg->otherpriority, 0);
+    if (prioritydiff || sectiondiff) 
+      addheading(thispkg->priority,thispkg->otherpriority,
+                 thispkg->section ? thispkg->section : "");
+    lastpkg= thispkg;
+  }
+
+  if (listpad) {
+    int maxx, maxy;
+    getmaxyx(listpad,maxx,maxy);
+    if (nitems > maxy) {
+      delwin(listpad);
+      listpad= newpad(nitems+1, total_width);
+      if (!listpad) ohshite("failed to create larger baselist pad");
+    } else if (nitems < maxy) {
+      werase(listpad);
+    }
+  }
+  
+  sortinplace();
+}
+
+void packagelist::initialsetup() {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::initialsetup()\n",this);
+
+  int allpackages= countpackages();
+  datatable= new struct perpackagestate[allpackages];
+
+  nallocated= allpackages+150; // will realloc if necessary, so 150 not critical
+  table= new struct perpackagestate*[nallocated];
+
+  depsdone= 0;
+  unavdone= 0;
+  currentinfo= 0;
+  headings= 0;
+  verbose= 0;
+}
+
+void packagelist::finalsetup() {
+  setcursor(0);
+
+  if (debug)
+    fprintf(debug,"packagelist[%p]::finalsetup done; recursive=%d nitems=%d\n",
+            this, recursive, nitems);
+}
+
+packagelist::packagelist(keybindings *kb) : baselist(kb) {
+  // nonrecursive
+  initialsetup();
+  struct pkgiterator *iter;
+  struct pkginfo *pkg;
+  
+  for (iter=iterpkgstart(), nitems=0;
+       (pkg=iterpkgnext(iter));
+       ) {
+    struct perpackagestate *state= &datatable[nitems];
+    state->pkg= pkg;
+    if (!informativeperfile(&pkg->available) &&
+        pkg->status == pkginfo::stat_notinstalled &&
+        pkg->priority == pkginfo::pri_unknown &&
+        !(pkg->section && *pkg->section) &&
+        !pkg->files &&
+        pkg->want != pkginfo::want_install) {
+      pkg->clientdata= 0; continue;
+    }
+    if (!pkg->available.valid) blankpackageperfile(&pkg->available);
+    state->direct= state->original= pkg->want;
+    if (readwrite && pkg->want == pkginfo::want_unknown) {
+      state->suggested= pkg->priority <= pkginfo::pri_standard
+        ? pkginfo::want_install : pkginfo::want_purge; /* fixme: configurable */
+      state->spriority= sp_inherit;
+    } else {
+      state->suggested= pkg->want;
+      state->spriority= sp_fixed;
+    }
+    state->dpriority= dp_must;
+    state->selected= state->suggested;
+    state->uprec= 0;
+    state->relations.init();
+    pkg->clientdata= state;
+    table[nitems]= state;
+    nitems++;
+  }
+  if (!nitems) ohshit("There are no packages to select.");
+  recursive= 0;
+  sortorder= so_priority;
+  sortmakeheads();
+  finalsetup();
+}
+
+packagelist::packagelist(keybindings *kb, pkginfo **pkgltab) : baselist(kb) {
+  // takes over responsibility for pkgltab (recursive)
+  initialsetup();
+  
+  recursive= 1;
+  nitems= 0;
+  if (pkgltab) {
+    add(pkgltab);
+    delete[] pkgltab;
+  }
+    
+  sortorder= so_unsorted;
+  finalsetup();
+}
+
+void perpackagestate::free(int recursive) {
+  if (pkg->name) {
+    if (readwrite) {
+      if (uprec) {
+        assert(recursive);
+        uprec->selected= selected;
+        pkg->clientdata= uprec;
+      } else {
+        assert(!recursive);
+        if (pkg->want != selected) {
+          pkg->want= selected;
+        }
+        pkg->clientdata= 0;
+      }
+    }
+    relations.free();
+  }
+}
+
+packagelist::~packagelist() {
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist()\n",this);
+
+  discardheadings();
+  
+  int index;
+  for (index=0; index<nitems; index++) table[index]->free(recursive);
+  delete[] table;
+  delete[] datatable;
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist() tables freed\n",this);
+  
+  doneent *search, *next;
+  for (search=depsdone; search; search=next) {
+    next= search->next;
+    delete search;
+  }
+  
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist() done\n",this);
+}
+
+pkginfo **packagelist::display() {
+  // returns list of packages as null-terminated array, which becomes owned
+  // by the caller, if a recursive check is desired.
+  // returns 0 if no recursive check is desired.
+  int response, index;
+  const keybindings::interpretation *interp;
+  pkginfo **retl;
+
+  if (debug) fprintf(debug,"packagelist[%p]::display()\n",this);
+
+  setupsigwinch();
+  startdisplay();
+  displayhelp(helpmenulist(),'i');
+
+  if (debug) fprintf(debug,"packagelist[%p]::display() entering loop\n",this);
+  for (;;) {
+    if (whatinfo_height) wcursyncup(whatinfowin);
+    if (doupdate() == ERR) ohshite("doupdate failed");
+    signallist= this;
+    if (sigprocmask(SIG_UNBLOCK,&sigwinchset,0)) ohshite("failed to unblock SIGWINCH");
+    response= getch();
+    if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to re-block SIGWINCH");
+    if (response == ERR) ohshite("getch failed");
+    interp= (*bindings)(response);
+    if (debug)
+      fprintf(debug,"packagelist[%p]::display() response=%d interp=%s\n",
+              this,response, interp ? interp->action : "[none]");
+    if (!interp) { beep(); continue; }
+    (this->*(interp->pfn))();
+    if (interp->qa != qa_noquit) break;
+  }
+  pop_cleanup(ehflag_normaltidy); // unset the SIGWINCH handler
+  enddisplay();
+  
+  if (interp->qa == qa_quitnochecksave || !readwrite) {
+    if (debug) fprintf(debug,"packagelist[%p]::display() done - quitNOcheck\n",this);
+    return 0;
+  }
+  
+  if (recursive) {
+    retl= new pkginfo*[nitems+1];
+    for (index=0; index<nitems; index++) retl[index]= table[index]->pkg;
+    retl[nitems]= 0;
+    if (debug) fprintf(debug,"packagelist[%p]::display() done, retl=%p\n",this,retl);
+    return retl;
+  } else {
+    packagelist *sub= new packagelist(bindings,0);
+    for (index=0; index < nitems; index++)
+      if (table[index]->pkg->name)
+        sub->add(table[index]->pkg);
+    repeatedlydisplay(sub,dp_must);
+    if (debug)
+      fprintf(debug,"packagelist[%p]::display() done, not recursive no retl\n",this);
+    return 0;
+  }
+}
diff --git a/dselect/pkglist.h b/dselect/pkglist.h
new file mode 100644 (file)
index 0000000..a1d045b
--- /dev/null
@@ -0,0 +1,183 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * pkglist.h - external definitions for package list handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PKGLIST_H
+#define PKGLIST_H
+
+enum showpriority {
+  dp_none,      // has not been involved in any unsatisfied things
+  dp_may,       // has been involved in an unsatisfied Optional
+  dp_must       // has been involved in an unsatisfied Recommended/Depends/Conflicts
+};
+
+enum selpriority {
+  // where did the currently suggested value come from, and how important
+  //  is it to display this package ?
+  // low
+  sp_inherit,     // inherited from our parent list
+  sp_selecting,   // propagating a selection
+  sp_deselecting, // propagating a deselection
+  sp_fixed        // it came from the `status' file and we're not a recursive list
+  // high
+};
+
+struct perpackagestate {
+  struct pkginfo *pkg;
+  /* The `heading' entries in the list, for `all packages of type foo',
+   * point to a made-up pkginfo, which has pkg->name==0.
+   * pkg->priority and pkg->section are set to the values if appropriate, or to
+   * pri_unset resp. null if the heading refers to all priorities resp. sections.
+   * uprec is used when constructing the list initially and when tearing it
+   * down and should not otherwise be used; other fields are undefined.
+   */
+  pkginfo::pkgwant original;         // set by caller
+  pkginfo::pkgwant direct;           // set by caller
+  pkginfo::pkgwant suggested;        // set by caller, modified by resolvesuggest
+  pkginfo::pkgwant selected;         // not set by caller, will be set by packagelist
+  selpriority spriority;             // monotonically increases (used by sublists)
+  showpriority dpriority;            // monotonically increases (used by sublists)
+  struct perpackagestate *uprec;     // 0 if this is not part of a recursive list
+  varbuf relations;
+
+  void free(int recursive);
+};
+
+class packagelist : public baselist {
+  int status_width, gap_width, section_width, priority_width;
+  int package_width, description_width;
+  int section_column, priority_column, package_column, description_column;
+
+  // Only used when `verbose' is set
+  int status_hold_width, status_status_width, status_want_width;
+
+  // Table of packages
+  struct perpackagestate *datatable;
+  struct perpackagestate **table;
+
+  // Misc.
+  int recursive, nallocated, verbose;
+  enum { so_unsorted, so_section, so_priority, so_alpha } sortorder;
+  struct perpackagestate *headings;
+
+  // Information displays
+  struct infotype {
+    int (packagelist::*relevant)(); // null means always relevant
+    void (packagelist::*display)(); // null means end of table
+  };
+  const infotype *currentinfo;
+  static const infotype infoinfos[];
+  static const infotype *const baseinfo;
+  int itr_recursive();
+  int itr_nonrecursive();
+  void severalinfoblurb(const char *whatinfoline);
+  void itd_mainwelcome();
+  void itd_explaindisplay();
+  void itd_recurwelcome();
+  void itd_relations();
+  void itd_description();
+  void itd_controlfile();
+  
+  // Dependency and sublist processing
+  struct doneent { doneent *next; void *dep; } *depsdone, *unavdone;
+  int alreadydone(doneent**, void*);
+  int resolvedepcon(dependency*);
+  int deselect_one_of(pkginfo *er, pkginfo *ed, dependency *display);
+  
+  // Define these virtuals
+  void redraw1itemsel(int index, int selected);
+  void redrawcolheads();
+  void redrawthisstate();
+  void redrawinfo();
+  void redrawtitle();
+  void setwidths();
+  const char *itemname(int index);
+  const struct helpmenuentry *helpmenulist();
+
+  // Miscellaneous internal routines
+  
+  void redraw1package(int index, int selected);
+  int compareentries(struct perpackagestate *a, struct perpackagestate *b);
+  friend int qsort_compareentries(const void *a, const void *b);
+
+  void sortmakeheads();
+  void movecursorafter(int ncursor);
+  void initialsetup();
+  void finalsetup();
+
+  // To do with building the list, with heading lines in it
+  void discardheadings();
+  void addheading(pkginfo::pkgpriority,const char*, const char *section);
+  void sortinplace();
+  void affectedrange(int *startp, int *endp);
+  void setwant(pkginfo::pkgwant nw);
+  void sethold(int hold);
+  
+ public:
+
+  // Keybinding functions */
+  void kd_quit_noop();
+  void kd_revert_abort();
+  void kd_revertsuggest();
+  void kd_revertdirect();  
+  void kd_morespecific();
+  void kd_lessspecific();
+  void kd_swaporder();
+  void kd_select();
+  void kd_deselect();
+  void kd_purge();
+  void kd_hold();
+  void kd_unhold();
+  void kd_info();
+  void kd_verbose();
+  
+  packagelist(keybindings *kb); // nonrecursive
+  packagelist(keybindings *kb, pkginfo **pkgltab); // recursive
+  void add(pkginfo **arry) { while (*arry) add(*arry++); }
+  void add(pkginfo*);
+  void add(pkginfo*, pkginfo::pkgwant);
+  void add(pkginfo*, const char *extrainfo, showpriority displayimportance);
+  int add(dependency*, showpriority displayimportance);
+  void addunavailable(deppossi*);
+
+  int resolvesuggest();
+  int deletelessimp_anyleft(showpriority than);
+  pkginfo **display();
+  ~packagelist();
+};
+
+void repeatedlydisplay(packagelist *sub, showpriority, packagelist *unredisplay =0);
+
+extern const char *const wantstrings[];
+extern const char *const holdstrings[];
+extern const char *const statusstrings[];
+extern const char *const prioritystrings[];
+extern const char *const priorityabbrevs[];
+extern const char *const relatestrings[];
+extern const char statuschars[];
+extern const char holdchars[];
+extern const char wantchars[];
+
+const struct pkginfoperfile *i2info(struct pkginfo *pkg);
+int deppossatisfied(deppossi *possi);
+
+extern modstatdb_rw readwrite;
+
+#endif /* PKGLIST_H */
diff --git a/dselect/pkgsublist.cc b/dselect/pkgsublist.cc
new file mode 100644 (file)
index 0000000..ccaf2e9
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgsublist.cc - status modification and recursive package list handling
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+void packagelist::add(pkginfo *pkg) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s)\n",this,pkg->name);
+  if (!recursive ||  // never add things to top level
+      !pkg->clientdata ||  // don't add pure virtual packages
+      pkg->clientdata->uprec)  // don't add ones already in the recursive list
+    return;
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s) adding\n",this,pkg->name);
+  perpackagestate *state= &datatable[nitems];
+  state->pkg= pkg;
+  state->direct= state->original= pkg->clientdata->selected;
+  state->suggested= state->selected= pkg->clientdata->selected;
+  state->spriority= sp_inherit; state->dpriority= dp_none;
+  state->uprec= pkg->clientdata;
+  state->relations.init();
+  pkg->clientdata= state;
+  table[nitems]= state;
+  nitems++;
+}   
+
+void packagelist::add(pkginfo *pkg, pkginfo::pkgwant nw) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s, %s)\n",
+                     this,pkg->name,wantstrings[nw]);
+  add(pkg);  if (!pkg->clientdata) return;
+  pkg->clientdata->direct= nw;
+  selpriority np;
+  np= (nw == pkginfo::want_install) ? sp_selecting : sp_deselecting;
+  if (pkg->clientdata->spriority > np) return;
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s, %s) setting\n",
+                     this,pkg->name,wantstrings[nw]);
+  pkg->clientdata->suggested= pkg->clientdata->selected= nw;
+  pkg->clientdata->spriority= np;
+    
+}   
+
+void packagelist::add(pkginfo *pkg, const char *extrainfo, showpriority showimp) {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::add(pkginfo %s, \"...\", showpriority %d)\n",
+            this,pkg->name,showimp);
+  add(pkg);  if (!pkg->clientdata) return;
+  if (pkg->clientdata->dpriority < showimp) pkg->clientdata->dpriority= showimp;
+  pkg->clientdata->relations(extrainfo);
+  pkg->clientdata->relations.terminate();
+}   
+
+int packagelist::alreadydone(doneent **done, void *check) {
+  doneent *search;
+  
+  for (search= *done; search && search->dep != check; search=search->next);
+  if (search) return 1;
+  if (debug) fprintf(debug,"packagelist[%p]::alreadydone(%p,%p) new\n",
+                     this,done,check);
+  search= new doneent;
+  search->next= *done;
+  search->dep= check;
+  *done= search;
+  return 0;
+}
+
+void packagelist::addunavailable(deppossi *possi) {
+  if (debug) fprintf(debug,"packagelist[%p]::addunavail(%p)\n",this,possi);
+
+  if (!recursive) return;
+  if (alreadydone(&unavdone,possi)) return;
+
+  assert(possi->up->up->clientdata);
+  assert(possi->up->up->clientdata->uprec);
+
+  varbuf& vb= possi->up->up->clientdata->relations;
+  vb(possi->ed->name);
+  vb(" does not appear to be available\n");
+}
+
+int packagelist::add(dependency *depends, showpriority displayimportance) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(dependency[%p])\n",this,depends);
+
+  if (alreadydone(&depsdone,depends)) return 0;
+  
+  const char *comma= "";
+  varbuf info;
+  info(depends->up->name);
+  info(' ');
+  info(relatestrings[depends->type]);
+  info(' ');
+  deppossi *possi;
+  for (possi=depends->list;
+       possi;
+       possi=possi->next, comma=(possi && possi->next ? ", " : " or ")) {
+    info(comma);
+    info(possi->ed->name);
+    if (possi->version && *possi->version) {
+      switch (possi->verrel) {
+      case deppossi::dvr_earlierequal:  info(" (<= "); break;
+      case deppossi::dvr_laterequal:    info(" (>= "); break;
+      case deppossi::dvr_earlierstrict: info(" (<< "); break;
+      case deppossi::dvr_laterstrict:   info(" (>> "); break;
+      case deppossi::dvr_exact:         info(" (= "); break;
+      default: internerr("unknown verrel");
+      }
+      info(possi->version);
+      if (possi->revision && *possi->revision) {
+        info('-');
+        info(possi->revision);
+      }
+      info(")");
+    }
+  }
+  info('\n');
+  add(depends->up,info.string(),displayimportance);
+  for (possi=depends->list; possi; possi=possi->next) {
+    add(possi->ed,info.string(),displayimportance);
+    if (depends->type != dep_provides && (!possi->version || !*possi->version)) {
+      // providers aren't relevant if a version was specified, or
+      // if we're looking at a provider relationship already
+      deppossi *provider;
+      for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+           provider;
+           provider=provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+        add(provider->up->up,info.string(),displayimportance);
+        add(provider->up,displayimportance);
+      }
+    }
+  }
+  return 1;
+}
+
+void repeatedlydisplay(packagelist *sub,
+                       showpriority initial,
+                       packagelist *unredisplay) {
+  pkginfo **newl;
+  keybindings *kb;
+  
+  if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p])\n",sub);
+  if (sub->resolvesuggest() != 0 && sub->deletelessimp_anyleft(initial)) {
+    if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) once\n",sub);
+    if (unredisplay) unredisplay->enddisplay();
+    for (;;) {
+      newl= sub->display();
+      if (!newl) break;
+      if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) newl\n",sub);
+      kb= sub->bindings; delete sub;
+      sub= new packagelist(kb,newl);
+      if (sub->resolvesuggest() <= 1) break;
+      if (!sub->deletelessimp_anyleft(dp_must)) break;
+      if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) again\n",sub);
+    }
+    if (unredisplay) unredisplay->startdisplay();
+  }
+  delete sub;
+  if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) done\n",sub);
+}
+
+int packagelist::deletelessimp_anyleft(showpriority than) {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::dli_al(%d): nitems=%d\n",this,than,nitems);
+  int insat, runthr;
+  for (runthr=0, insat=0;
+       runthr < nitems;
+       runthr++) {
+    if (table[runthr]->dpriority < than) {
+      table[runthr]->free(recursive);
+    } else {
+      if (insat != runthr) table[insat]= table[runthr];
+      insat++;
+    }
+  }
+  nitems= insat;
+  if (debug) fprintf(debug,"packagelist[%p]::dli_al(%d) done; nitems=%d\n",
+                     this,than,nitems);
+  return nitems;
+}
diff --git a/dselect/pkgtop.cc b/dselect/pkgtop.cc
new file mode 100644 (file)
index 0000000..845b5dd
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgtop.cc - handles (re)draw of package list windows colheads, list, thisstate
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+const char *pkgprioritystring(const struct pkginfo *pkg) {
+  if (pkg->priority == pkginfo::pri_unset) {
+    return 0;
+  } else if (pkg->priority == pkginfo::pri_other) {
+    return pkg->otherpriority;
+  } else {
+    assert(pkg->priority <= pkginfo::pri_unknown);
+    return prioritystrings[pkg->priority];
+  }
+}
+
+static int describemany(char buf[], const char *prioritystring, const char *section) {
+  if (!prioritystring) {
+    if (!section) {
+      strcpy(buf, "All packages");
+      return 0;
+    } else {
+      if (!*section) {
+        strcpy(buf, "All packages without a section");
+      } else {
+        sprintf(buf, "All packages in section %s", section);
+      }
+      return 1;
+    }
+  } else {
+    if (!section) {
+      sprintf(buf, "All %s packages", prioritystring);
+      return 1;
+    } else {
+      if (!*section) {
+        sprintf(buf, "All %s packages without a section", prioritystring);
+      } else {
+        sprintf(buf, "All %s packages in section %s", prioritystring, section);
+      }
+      return 2;
+    }
+  }
+}
+
+void packagelist::redrawthisstate() {
+  if (!thisstate_height) return;
+  mywerase(thisstatepad);
+
+  const char *section= table[cursorline]->pkg->section;
+  const char *priority= pkgprioritystring(table[cursorline]->pkg);
+  char *buf= new char[220+
+                      greaterint((table[cursorline]->pkg->name
+                                  ? strlen(table[cursorline]->pkg->name) : 0),
+                                 (section ? strlen(section) : 0) +
+                                 (priority ? strlen(priority) : 0))];
+    
+  if (table[cursorline]->pkg->name) {
+    sprintf(buf,
+            "%-*s %s%s%s;  %s (was: %s).  %s",
+            package_width,
+            table[cursorline]->pkg->name,
+            statusstrings[table[cursorline]->pkg->status],
+            holdstrings[table[cursorline]->pkg->eflag][0] ? " - " : "",
+            holdstrings[table[cursorline]->pkg->eflag],
+            wantstrings[table[cursorline]->selected],
+            wantstrings[table[cursorline]->original],
+            priority);
+  } else {
+    describemany(buf,priority,section);
+  }
+  mvwaddnstr(thisstatepad,0,0, buf, total_width);
+  pnoutrefresh(thisstatepad, 0,leftofscreen, thisstate_row,0,
+               thisstate_row, lesserint(total_width - 1, xmax - 1));
+
+  delete[] buf;
+}
+
+void packagelist::redraw1itemsel(int index, int selected) {
+  int i, indent, j;
+  const char *p;
+  const struct pkginfo *pkg= table[index]->pkg;
+  const struct pkginfoperfile *info= &pkg->available;
+
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+
+  if (pkg->name) {
+
+    if (verbose) {
+
+      mvwprintw(listpad,index,0, "%-*.*s ",
+                status_hold_width, status_hold_width,
+                holdstrings[pkg->eflag]);
+      wprintw(listpad, "%-*.*s ",
+              status_status_width, status_status_width,
+              statusstrings[pkg->status]);
+      wprintw(listpad, "%-*.*s ",
+              status_want_width, status_want_width,
+              /* fixme: keep this ? */
+              /*table[index]->original == table[index]->selected ? "(same)"
+              : */wantstrings[table[index]->original]);
+      wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+      wprintw(listpad, "%-*.*s",
+              status_want_width, status_want_width,
+              wantstrings[table[index]->selected]);
+      wattrset(listpad, selected ? listsel_attr : list_attr);
+      waddch(listpad, ' ');
+  
+      mvwprintw(listpad,index,priority_column-1, " %-*.*s",
+                priority_width, priority_width,
+                pkg->priority == pkginfo::pri_other ? pkg->otherpriority :
+                prioritystrings[pkg->priority]);
+
+    } else {
+
+      mvwaddch(listpad,index,0, holdchars[pkg->eflag]);
+      waddch(listpad, statuschars[pkg->status]);
+      waddch(listpad,
+             /* fixme: keep this feature? */
+             /*table[index]->original == table[index]->selected ? ' '
+             : */wantchars[table[index]->original]);
+    
+      wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+      waddch(listpad, wantchars[table[index]->selected]);
+      wattrset(listpad, selected ? listsel_attr : list_attr);
+      
+      wmove(listpad,index,priority_column-1); waddch(listpad,' ');
+      if (pkg->priority == pkginfo::pri_other) {
+        int i;
+        char *p;
+        for (i=priority_width, p=pkg->otherpriority;
+             i > 0 && *p;
+             i--, p++)
+          waddch(listpad, tolower(*p));
+        while (i-- > 0) waddch(listpad,' ');
+      } else {
+        wprintw(listpad, "%-*.*s", priority_width, priority_width,
+                priorityabbrevs[pkg->priority]);
+      }
+
+    }
+
+    mvwprintw(listpad,index,section_column-1, " %-*.*s",
+              section_width, section_width,
+              pkg->section ? pkg->section : "?");
+  
+    mvwprintw(listpad,index,package_column-1, " %-*.*s ",
+              package_width, package_width, pkg->name);
+      
+    i= description_width;
+    p= info->description ? info->description : "";
+    while (i>0 && *p && *p != '\n') { waddch(listpad,*p); i--; p++; }
+      
+  } else {
+
+    const char *section= pkg->section;
+    const char *priority= pkgprioritystring(pkg);
+
+    char *buf= new char[220+
+                        (section ? strlen(section) : 0) +
+                        (priority ? strlen(priority) : 0)];
+    
+    indent= describemany(buf,priority,section);
+
+    mvwaddstr(listpad,index,0, "    ");
+    i= total_width-6;
+    j= (indent<<1) + 1;
+    while (j-- >0) { waddch(listpad,'-'); i--; }
+    waddch(listpad,' ');
+
+    wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+    p= buf;
+    while (i>0 && *p) { waddch(listpad, *p); p++; i--; }
+    wattrset(listpad, selected ? listsel_attr : list_attr);
+
+    waddch(listpad,' ');
+    j= (indent<<1) + 1;
+    while (j-- >0) { waddch(listpad,'-'); i--; }
+
+    delete[] buf;
+
+  }
+
+  while (i>0) { waddch(listpad,' '); i--; }
+}
+
+void packagelist::redrawcolheads() {
+  if (colheads_height) {
+    wattrset(colheadspad,colheads_attr);
+    mywerase(colheadspad);
+    if (verbose) {
+      wmove(colheadspad,0,0);
+      for (int i=0; i<status_width-status_want_width; i++) waddch(colheadspad,'.');
+      mvwaddnstr(colheadspad,0,
+                 0,
+                 "Hold/Err.",
+                 status_hold_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+1,
+                 "Installed?",
+                 status_status_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+status_status_width+2,
+                 "Old sel.",
+                 status_want_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+status_status_width+status_want_width+3,
+                 "Selection",
+                 status_want_width);
+    } else {
+      mvwaddstr(colheadspad,0,0, "HIOS");
+    }
+    mvwaddnstr(colheadspad,0,section_column, "Section", section_width);
+    mvwaddnstr(colheadspad,0,priority_column, "Priority", priority_width);
+    mvwaddnstr(colheadspad,0,package_column, "Package", package_width);
+    mvwaddnstr(colheadspad,0,description_column, "Description", description_width);
+  }
+  refreshcolheads();
+}
diff --git a/dselect/rp b/dselect/rp
new file mode 100755 (executable)
index 0000000..6323488
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+while cat p; do echo ===================; done
diff --git a/dselect/t.c b/dselect/t.c
new file mode 100644 (file)
index 0000000..c324412
--- /dev/null
@@ -0,0 +1 @@
+#include <ncurses/curses.h>
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644 (file)
index 0000000..b2c0ddc
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+all:
+
+clean:
+               rm -f core
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
diff --git a/include/dpkg-db.h b/include/dpkg-db.h
new file mode 100644 (file)
index 0000000..5918858
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg-db.h - declarations for in-core package database management
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_DB_H
+#define DPKG_DB_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+enum deptype {
+  dep_suggests,
+  dep_recommends,
+  dep_depends,
+  dep_predepends,
+  dep_conflicts,
+  dep_provides,
+  dep_replaces
+};
+
+struct dependency { /* dy */
+  struct pkginfo *up;
+  struct dependency *next;
+  struct deppossi *list;
+  enum deptype type;
+};
+
+struct deppossi { /* do */
+  struct dependency *up;
+  struct pkginfo *ed;
+  struct deppossi *next, *nextrev, *backrev;
+  enum depverrel {
+    dvrf_earlier=      0001,
+    dvrf_later=        0002,
+    dvrf_strict=       0010,
+    dvrf_orequal=      0020,
+    dvrf_builtup=      0100,
+    dvr_none=          0200,
+    dvr_earlierequal=  dvrf_builtup | dvrf_earlier | dvrf_orequal,
+    dvr_earlierstrict= dvrf_builtup | dvrf_earlier | dvrf_strict,
+    dvr_laterequal=    dvrf_builtup | dvrf_later   | dvrf_orequal,
+    dvr_laterstrict=   dvrf_builtup | dvrf_later   | dvrf_strict,
+    dvr_exact=         0400
+  } verrel;
+  char *version, *revision;
+  int cyclebreak;
+};
+
+struct arbitraryfield {
+  struct arbitraryfield *next;
+  char *name;
+  char *value;
+};
+
+struct conffile {
+  struct conffile *next;
+  char *name;
+  char *hash;
+};
+
+struct filedetails {
+  struct filedetails *next;
+  char *name, *msdosname, *size, *md5sum;
+};
+
+struct pkginfoperfile { /* pif */
+  int valid;
+  struct dependency *depends;
+  struct deppossi *depended;
+  int essential; /* The `essential' flag, 1=yes, 0=no (absent) */
+  char *description, *maintainer, *version, *revision, *source, *architecture;
+  struct conffile *conffiles;
+  struct arbitraryfield *arbs;
+};
+
+struct perpackagestate; /* used by dselect only, but we keep a pointer here */
+
+struct pkginfo { /* pig */
+  struct pkginfo *next;
+  char *name;
+  enum pkgwant {
+    want_unknown, want_install, want_deinstall, want_purge
+  } want;
+  enum pkgeflag {
+    eflagv_ok=00, eflagv_hold=01, eflagv_reinstreq=02, eflagv_both=03,
+    eflagf_hold=01, eflagf_reinstreq=02
+  } eflag; /* bitmask */
+  enum pkgstatus {
+    stat_notinstalled, stat_unpacked, stat_halfconfigured,
+    stat_installed, stat_halfinstalled, stat_configfiles
+  } status;
+  enum pkgpriority {
+    pri_required, pri_important, pri_standard, pri_recommended,
+    pri_optional, pri_extra, pri_contrib,
+    pri_other, pri_unknown, pri_unset=-1
+  } priority;
+  char *otherpriority;
+  char *section;
+  char *configversion, *configrevision;
+  struct filedetails *files;
+  struct pkginfoperfile installed;
+  struct pkginfoperfile available;
+  struct perpackagestate *clientdata;
+};
+
+/*** from lock.c ***/
+
+void lockdatabase(const char *admindir);
+void unlockdatabase(const char *admindir);
+
+/*** from dbmodify.c ***/
+
+enum modstatdb_rw {
+  /* Those marked with \*s*\ are possible returns from modstatdb_init. */
+  msdbrw_readonly/*s*/, msdbrw_needsuperuserlockonly/*s*/,
+  msdbrw_writeifposs,
+  msdbrw_write/*s*/, msdbrw_needsuperuser,
+  /* Now some optional flags: */
+  msdbrw_flagsmask= ~077,
+  /* Prefer later versions from `status' in `available' info, but do not
+   * save `available' info: */
+  msdbrw_availablepreferversion= 0100
+};
+
+enum modstatdb_rw modstatdb_init(const char *admindir, enum modstatdb_rw reqrwflags);
+void modstatdb_note(struct pkginfo *pkg);
+void modstatdb_shutdown(void);
+
+extern char *statusfile, *availablefile; /* initialised by modstatdb_init */
+
+/*** from database.c ***/
+
+struct pkginfo *findpackage(const char *name);
+void blankpackage(struct pkginfo *pp);
+void blankpackageperfile(struct pkginfoperfile *pifp);
+int informative(struct pkginfo *info);
+int informativeperfile(struct pkginfoperfile *info);
+int countpackages(void);
+void resetpackages(void);
+
+struct pkgiterator *iterpkgstart(void);
+struct pkginfo *iterpkgnext(struct pkgiterator*);
+void iterpkgend(struct pkgiterator*);
+
+void hashreport(FILE*);
+
+/*** from parse.c ***/
+
+enum parsedbflags {
+  pdb_recordavailable   =001, /* Store in `available' in-core structures, not `status' */
+  pdb_rejectstatus      =002, /* Throw up an error if `Status' encountered             */
+  pdb_weakclassification=004, /* Ignore priority/section info if we already have any   */
+  pdb_preferversion=     010  /* Discard information about earlier versions            */
+};
+
+const char *illegal_packagename(const char *p, const char **ep);
+int parsedb(const char *filename, enum parsedbflags, struct pkginfo **donep,
+            FILE *warnto, int *warncount);
+void copy_dependency_links(struct pkginfo *pkg,
+                           struct dependency **updateme,
+                           struct dependency *newdepends,
+                           int available);
+
+/*** from parsehelp.c ***/
+
+struct namevalue {
+  const char *name;
+  int value;
+};
+
+extern const struct namevalue booleaninfos[];
+extern const struct namevalue priorityinfos[];
+extern const struct namevalue statusinfos[];
+extern const struct namevalue eflaginfos[];
+extern const struct namevalue wantinfos[];
+
+const char *skip_slash_dotslash(const char *p);
+
+/*** from varbuf.c ***/
+
+struct varbuf;
+
+extern void varbufaddc(struct varbuf *v, int c);
+void varbufinit(struct varbuf *v);
+void varbufreset(struct varbuf *v);
+void varbufextend(struct varbuf *v);
+void varbuffree(struct varbuf *v);
+void varbufaddstr(struct varbuf *v, const char *s);
+
+/* varbufinit must be called exactly once before the use of each varbuf
+ * (including before any call to varbuffree).
+ *
+ * However, varbufs allocated `static' are properly initialised anyway and
+ * do not need varbufinit; multiple consecutive calls to varbufinit before
+ * any use are allowed.
+ *
+ * varbuffree must be called after a varbuf is finished with, if anything
+ * other than varbufinit has been done.  After this you are allowed but
+ * not required to call varbufinit again if you want to start using the
+ * varbuf again.
+ *
+ * Callers using C++ need not worry about any of this.
+ */
+struct varbuf {
+  int used, size;
+  char *buf;
+
+#ifdef __cplusplus
+  void init() { varbufinit(this); }
+  void free() { varbuffree(this); }
+  varbuf() { varbufinit(this); }
+  ~varbuf() { varbuffree(this); }
+  inline void operator()(int c); // definition below
+  void operator()(const char *s) { varbufaddstr(this,s); }
+  inline void terminate(void/*to shut 2.6.3 up*/); // definition below
+  void reset() { used=0; }
+  const char *string() { terminate(); return buf; }
+#endif
+};
+
+#if HAVE_INLINE
+inline extern void varbufaddc(struct varbuf *v, int c) {
+  if (v->used >= v->size) varbufextend(v);
+  v->buf[v->used++]= c;
+}
+#endif
+
+#ifdef __cplusplus
+inline void varbuf::operator()(int c) { varbufaddc(this,c); }
+inline void varbuf::terminate(void/*to shut 2.6.3 up*/) { varbufaddc(this,0); used--; }
+#endif
+
+/*** from dump.c ***/
+
+void writerecord(FILE*, const char*,
+                 const struct pkginfo*, const struct pkginfoperfile*);
+
+void writedb(const char *filename, int available, int mustsync);
+
+void varbufrecord(struct varbuf*, const struct pkginfo*, const struct pkginfoperfile*);
+void varbufdependency(struct varbuf *vb, struct dependency *dep);
+  /* NB THE VARBUF MUST HAVE BEEN INITIALISED AND WILL NOT BE NULL-TERMINATED */
+
+/*** from vercmp.c ***/
+
+int versioncompare(const char *version, const char *revision,
+                   const char *refversion, const char *refrevision);
+
+/*** from nfmalloc.c ***/
+
+void *nfmalloc(size_t);
+char *nfstrsave(const char*);
+void nffreeall(void);
+
+#endif /* DPKG_DB_H */
diff --git a/include/dpkg.h b/include/dpkg.h
new file mode 100644 (file)
index 0000000..937c535
--- /dev/null
@@ -0,0 +1,179 @@
+
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg.h - general header for Debian package handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_H
+#define DPKG_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#define ARCHIVEVERSION     "2.0"
+#define SPLITVERSION       "2.1"
+#define OLDARCHIVEVERSION  "0.939000"
+#define SPLITPARTDEFMAX    (450*1024)
+#define MAXFIELDNAME        200
+#define MAXCONFFILENAME     1000
+#define MAXDIVERTFILENAME   1024
+#define MAXCONTROLFILENAME  100
+#define BUILDCONTROLDIR    "DEBIAN"
+#define EXTRACTCONTROLDIR   BUILDCONTROLDIR
+#define DEBEXT             ".deb"
+#define OLDDBEXT           "-old"
+#define NEWDBEXT           "-new"
+#define OLDOLDDEBDIR       ".DEBIAN"
+#define OLDDEBDIR          "DEBIAN"
+#define REMOVECONFFEXTS    "~", ".bak", "%", \
+                           DPKGTEMPEXT, DPKGNEWEXT, DPKGOLDEXT, DPKGDISTEXT
+
+#define DPKG_VERSION_ARCH  DPKG_VERSION " (" ARCHITECTURE ")"
+
+#define NEWCONFFILEFLAG    "newconffile"
+#define NONEXISTENTFLAG    "nonexistent"
+
+#define DPKGTEMPEXT        ".dpkg-tmp"
+#define DPKGNEWEXT         ".dpkg-new"
+#define DPKGOLDEXT         ".dpkg-old"
+#define DPKGDISTEXT        ".dpkg-dist"
+
+#define CONTROLFILE        "control"
+#define CONFFILESFILE      "conffiles"
+#define PREINSTFILE        "preinst"
+#define POSTINSTFILE       "postinst"
+#define PRERMFILE          "prerm"
+#define POSTRMFILE         "postrm"
+#define LISTFILE           "list"
+
+#define ADMINDIR        "/var/lib/dpkg"
+#define STATUSFILE      "status"
+#define AVAILFILE       "available"
+#define LOCKFILE        "lock"
+#define CMETHOPTFILE    "cmethopt"
+#define METHLOCKFILE    "methlock"
+#define DIVERSIONSFILE  "diversions"
+#define UPDATESDIR      "updates/"
+#define INFODIR         "info/"
+#define PARTSDIR        "parts/"
+#define CONTROLDIRTMP   "tmp.ci/"
+#define IMPORTANTTMP    "tmp.i"
+#define REASSEMBLETMP   "reassemble" DEBEXT
+#define IMPORTANTMAXLEN  10
+#define IMPORTANTFMT    "%04d" /* change => also change lib/database.c:cleanup_updates */
+#define MAXUPDATES       50
+
+#define LIBDIR              "/usr/lib/dpkg"
+#define LOCALLIBDIR         "/usr/local/lib/dpkg"
+#define METHODSDIR          "methods"
+
+#define NOJOBCTRLSTOPENV    "DPKG_NO_TSTP"
+#define SHELLENV            "SHELL"
+#define DEFAULTSHELL        "sh"
+
+#define IMETHODMAXLEN        50
+#define IOPTIONMAXLEN        IMETHODMAXLEN
+#define METHODOPTIONSFILE   "names"
+#define METHODSETUPSCRIPT   "setup"
+#define METHODUPDATESCRIPT  "update"
+#define METHODINSTALLSCRIPT "install"
+#define OPTIONSDESCPFX      "desc."
+#define OPTIONINDEXMAXLEN    5
+
+#define PKGSCRIPTMAXARGS     10
+#define MD5HASHLEN           32
+
+#define CONFFOPTCELLS  /* int conffoptcells[2] {* 1= user edited *}              \
+                                           [2] {* 1= distributor edited *} = */  \
+                                  /* dist not */     /* dist edited */           \
+   /* user did not edit */    {     cfo_keep,           cfo_install    },        \
+   /* user did edit     */    {     cfo_keep,         cfo_prompt_keep  }
+
+#define ARCHIVE_FILENAME_PATTERN "*.deb"
+
+#define BACKEND      "dpkg-deb"
+#define SPLITTER     "dpkg-split"
+#define MD5SUM       "md5sum"
+#define DSELECT      "dselect"
+#define DPKG         "dpkg"
+
+#define TAR          "tar"
+#define GZIP         "gzip"
+#define CAT          "cat"
+#define RM           "rm"
+#define FIND         "find"
+#define SHELL        "sh"
+
+#define SHELLENVIR   "SHELL"
+
+#define FIND_EXPRSTARTCHARS "-(),!"
+
+#define TARBLKSZ     512
+
+extern const char thisname[]; /* defined separately in each program */
+extern const char printforhelp[];
+
+/*** from ehandle.c ***/
+
+void push_error_handler(jmp_buf *jbufp,
+                        void (*printerror)(const char *, const char *),
+                        const char *contextstring);
+void set_error_display(void (*printerror)(const char *, const char *),
+                       const char *contextstring);
+void print_error_fatal(const char *emsg, const char *contextstring);
+void error_unwind(int flagset);
+void push_cleanup(void (*f1)(int argc, void **argv), int flagmask1,
+                  void (*f2)(int argc, void **argv), int flagmask2,
+                  int nargs, ...);
+void push_checkpoint(int mask, int value);
+void pop_cleanup(int flagset);
+enum { ehflag_normaltidy=01, ehflag_bombout=02, ehflag_recursiveerror=04 };
+
+void do_internerr(const char *string, int line, const char *file) NONRETURNING;
+#define internerr(s) do_internerr(s,__LINE__,__FILE__)
+
+struct varbuf;
+void ohshit(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void ohshitv(const char *fmt, va_list al) NONRETURNING;
+void ohshite(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void ohshitvb(struct varbuf*) NONRETURNING;
+void badusage(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void werr(const char *what) NONRETURNING;
+
+/*** from mlib.c ***/
+
+void *m_malloc(size_t);
+void *m_realloc(void*, size_t);
+int m_fork(void);
+void m_dup2(int oldfd, int newfd);
+void m_pipe(int fds[2]);
+
+void checksubprocerr(int status, const char *description, int sigpipeok);
+void waitsubproc(pid_t pid, const char *description, int sigpipeok);
+
+extern volatile int onerr_abort;
+
+/*** from showcright.c ***/
+
+struct cmdinfo;
+void showcopyright(const struct cmdinfo*, const char*);
+
+#endif /* DPKG_H */
diff --git a/include/myopt.h b/include/myopt.h
new file mode 100644 (file)
index 0000000..f7984d2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.h - declarations for my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MYOPT_H
+#define MYOPT_H
+
+struct cmdinfo {
+  const char *olong;
+  char oshort;
+  int takesvalue; /* 0 = normal   1 = standard value   2 = option string cont */
+  int *iassignto;
+  const char **sassignto;
+  void (*call)(const struct cmdinfo*, const char *value);
+  int arg;
+  void *parg;
+};
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos);
+
+#endif /* MYOPT_H */
diff --git a/include/tarfn.h b/include/tarfn.h
new file mode 100644 (file)
index 0000000..5e387b0
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef        _TAR_FUNCTION_H_
+#define        _TAR_FUNCTION_H_
+
+/*
+ * Functions for extracting tar archives.
+ * Bruce Perens, April-May 1995
+ * Copyright (C) 1995 Bruce Perens
+ * This is free software under the GNU General Public License.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+enum TarFileType {
+       NormalFile0 = '\0',     /* For compatibility with decades-old bug */
+       NormalFile1 = '0',
+       HardLink = '1',
+       SymbolicLink = '2',
+       CharacterDevice = '3',
+       BlockDevice = '4',
+       Directory = '5',
+       FIFO = '6'
+};
+typedef enum TarFileType       TarFileType;
+
+struct TarInfo {
+       void *          UserData;       /* User passed this in as argument */
+       char *          Name;           /* File name */
+       mode_t          Mode;           /* Unix mode, including device bits. */
+       size_t          Size;           /* Size of file */
+       time_t          ModTime;        /* Last-modified time */
+       TarFileType     Type;           /* Regular, Directory, Special, Link */
+       char *          LinkName;       /* Name for symbolic and hard links */
+       dev_t           Device;         /* Special device for mknod() */
+       uid_t           UserID;         /* Numeric UID */
+       gid_t           GroupID;        /* Numeric GID */
+};
+typedef struct TarInfo TarInfo;
+
+typedef        int     (*TarReadFunction)(void * userData, char * buffer, int length);
+
+typedef int    (*TarFunction)(TarInfo * h);
+
+struct TarFunctions {
+       TarReadFunction Read;
+       TarFunction     ExtractFile;
+       TarFunction     MakeDirectory;
+       TarFunction     MakeHardLink;
+       TarFunction     MakeSymbolicLink;
+       TarFunction     MakeSpecialFile;
+};
+typedef struct TarFunctions    TarFunctions;
+
+extern int     TarExtractor(void * userData, const TarFunctions * functions);
+
+#endif
diff --git a/insert-version.pl b/insert-version.pl
new file mode 100755 (executable)
index 0000000..4b1451d
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/perl --
+chop($v=`pwd`);
+$v =~ s,^.*/dpkg-,, || die;
+$v =~ s,/\w+$,,;
+$v =~ m,^[-0-9.]+$, || die;
+while (<STDIN>) {
+    $_= $1.$v.$2."\n" if
+        m|^(#define DPKG_VERSION ")[-0-9.]+(" /\* This line modified by Makefile \*/)$|;
+    $_= $1.$v.$2."\n" if
+        m/^(\$version= ')[-0-9.]+('; # This line modified by Makefile)$/;
+    $_= $1.$v.$2."\n" if
+        m/^(version=")[-0-9.]+("; # This line modified by Makefile)$/;
+    print || die;
+}
diff --git a/install.sh b/install.sh
new file mode 100755 (executable)
index 0000000..0ff4b6a
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+       echo "install:  no destination specified"
+       exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+       dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644 (file)
index 0000000..076c1ae
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+copyingfile = $(prefix)/doc/copyright/dpkg
+
+SRC =  ehandle.c mlib.c parse.c parsehelp.c fields.c dump.c nfmalloc.c \
+       varbuf.c database.c myopt.c vercmp.c compat.c lock.c dbmodify.c \
+       showcright.c tarfn.c star.c
+OBJ =  ehandle.o mlib.o parse.o parsehelp.o fields.o dump.o nfmalloc.o \
+       varbuf.o database.o myopt.o vercmp.o compat.o lock.o dbmodify.o \
+       showcright.o tarfn.o star.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ $(XCFLAGS) -g # fixme: remove -g
+OPTCFLAGS = @OPTCFLAGS@
+LDFLAGS = -s $(XLDFLAGS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+ALL_CFLAGS_OPT = $(ALL_CFLAGS) $(OPTCFLAGS)
+
+AR = ar crv
+RANLIB = @RANLIB@
+
+.SUFFIXES:     .c .o
+
+all:           libdpkg.a
+
+libdpkg.a:     $(OBJ)
+               $(AR) libdpkg.a $(OBJ)
+               $(RANLIB) libdpkg.a
+
+showcright.o:  showcright.c
+               $(CC) -DCOPYINGFILE=\"$(copyingfile)\" $(ALL_CFLAGS) -c $<
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+# These next few files are very heavily used, and should be optimised
+# for speed rather than space.  (ALL_CFLAGS_OPT usually means -O3.)
+database.o:    database.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+fields.o:      fields.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+nfmalloc.o:    nfmalloc.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+parse.o:       parse.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+parsehelp.o:   parsehelp.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+varbuf.o:      varbuf.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+clean:
+               rm -f *.o core libdpkg.a
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
+
+dump.o fields.o parse.o parsehelp.o vercmp.o:  parsedump.h
+$(OBJ):                        ../include/dpkg.h ../include/dpkg-db.h
+myopt.o:               ../include/myopt.h
+tarfn.o star.o:                ../include/tarfn.h
diff --git a/lib/compat.c b/lib/compat.c
new file mode 100644 (file)
index 0000000..94ae403
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * compat.c - compatibility functions
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "config.h"
+
+#ifndef HAVE_STRERROR
+extern const char *const sys_errlist[];
+extern const int sys_nerr;
+const char *strerror(int e) {
+  static char buf[100];
+  if (e >= 0 && e < sys_nerr) return sys_errlist[e];
+  sprintf(buf, "System error no.%d", e);
+  return buf;
+}
+#endif
+
+#ifndef HAVE_STRSIGNAL
+extern const char *const sys_siglist[];
+const char *strsignal(int e) {
+  static char buf[100];
+  if (e >= 0 && e < NSIG) return sys_siglist[e];
+  sprintf(buf, "Signal no.%d", e);
+  return buf;
+}
+#endif
+
+#ifndef HAVE_SCANDIR
+
+static int (*scandir_comparfn)(const void*, const void*);
+static int scandir_compar(const void *a, const void *b) {
+  return scandir_comparfn(*(const struct dirent**)a,*(const struct dirent**)b);
+}
+      
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*)) {
+  DIR *d;
+  int used, avail;
+  struct dirent *e, *m;
+  d= opendir(dir);  if (!d) return -1;
+  used=0; avail=20;
+  *namelist= malloc(avail*sizeof(struct dirent*));
+  if (!*namelist) return -1;
+  while ((e= readdir(d)) != 0) {
+    if (!select(e)) continue;
+    m= malloc(sizeof(struct dirent) + strlen(e->d_name));
+    if (!m) return -1;
+    *m= *e;
+    strcpy(m->d_name,e->d_name);
+    if (used >= avail-1) {
+      avail+= avail;
+      *namelist= realloc(*namelist, avail*sizeof(struct dirent*));
+      if (!*namelist) return -1;
+    }
+    (*namelist)[used]= m;
+    used++;
+  }
+  (*namelist)[used]= 0;
+  scandir_comparfn= compar;
+  qsort(*namelist, used, sizeof(struct dirent*), scandir_compar);
+  return used;
+}
+#endif
+
+#ifndef HAVE_ALPHASORT
+int alphasort(const struct dirent *a, const struct dirent *b) {
+  return strcmp(a->d_name,b->d_name);
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *p) {
+  char *q;
+  q= malloc(strlen(p)+3); if (!q) return;
+  strcpy(q,p); strcat(q,"="); putenv(q);
+}
+#endif
diff --git a/lib/database.c b/lib/database.c
new file mode 100644 (file)
index 0000000..9561a0f
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg-db.h - Low level package database routines (hash tables, etc.)
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+#define BINS (1 << 7)
+ /* This must always be a power of two.  If you change it
+  * consider changing the per-character hashing factor (currently 5) too.
+  */
+
+static struct pkginfo *bins[BINS];
+static int npackages;
+
+static int hash(const char *name) {
+  int v= 0;
+  while (*name) { v *= 5; v += tolower(*name); name++; }
+  return v;
+/* These results were achieved with 128 bins, and the list of packages
+ * shown at the bottom of this file.
+ */
+/*  while (*name) { v *= 17; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     0 times
+ *  size       3 occurs     7 times
+ *  size       2 occurs    32 times
+ *  size       1 occurs    51 times
+ *  size       0 occurs    37 times
+ */
+/*  while (*name) { v *= 5; v += tolower(*name); name++; }
+ *  size       4 occurs     1 times
+ *  size       3 occurs    14 times
+ *  size       2 occurs    20 times
+ *  size       1 occurs    55 times
+ *  size       0 occurs    38 times
+ */
+/*  while (*name) { v *= 11; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     4 times
+ *  size       3 occurs     9 times
+ *  size       2 occurs    25 times
+ *  size       1 occurs    43 times
+ *  size       0 occurs    46 times
+ */
+/*  while (*name) { v *= 31; v += tolower(*name); name++; }
+ *  size       6 occurs     1 times
+ *  size       5 occurs     0 times
+ *  size       4 occurs     1 times
+ *  size       3 occurs    11 times
+ *  size       2 occurs    27 times
+ *  size       1 occurs    44 times
+ *  size       0 occurs    44 times
+ */
+/*  while (*name) { v *= 111; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     1 times
+ *  size       3 occurs    14 times
+ *  size       2 occurs    23 times
+ *  size       1 occurs    44 times
+ *  size       0 occurs    45 times
+ */
+/*  while (*name) { v += (v<<3); v += tolower(*name); name++; }
+ *  size       4 occurs     5 times
+ *  size       3 occurs    12 times
+ *  size       2 occurs    22 times
+ *  size       1 occurs    41 times
+ *  size       0 occurs    48 times
+ */
+/*  while (*name) { v *= 29; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     2 times
+ *  size       3 occurs    10 times
+ *  size       2 occurs    26 times
+ *  size       1 occurs    46 times
+ *  size       0 occurs    43 times
+ */
+/*  while (*name) { v *= 13; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     2 times
+ *  size       3 occurs     5 times
+ *  size       2 occurs    30 times
+ *  size       1 occurs    53 times
+ *  size       0 occurs    37 times
+ */
+}
+
+void blankpackage(struct pkginfo *pigp) {
+  pigp->name= 0;
+  pigp->status= stat_notinstalled;
+  pigp->eflag= eflagv_ok;
+  pigp->want= want_unknown;
+  pigp->priority= pri_unknown;
+  pigp->section= pigp->configversion= pigp->configrevision= 0;
+  pigp->files= 0;
+  pigp->installed.valid= 0;
+  pigp->available.valid= 0;
+  pigp->clientdata= 0;
+}
+
+void blankpackageperfile(struct pkginfoperfile *pifp) {
+  pifp->essential= 0;
+  pifp->depends= 0;
+  pifp->depended= 0;
+  pifp->description= pifp->maintainer= pifp->source= 0;
+  pifp->architecture= pifp->version= pifp->revision= 0;
+  pifp->conffiles= 0;
+  pifp->arbs= 0;
+  pifp->valid= 1;
+}
+
+static int nes(const char *s) { return s && *s; }
+
+int informativeperfile(struct pkginfoperfile *info) {
+  /* Used by dselect as an aid to decide whether to display things. */
+  if (!info->valid) return 0;
+  if (info->depends ||
+      nes(info->description) ||
+      nes(info->maintainer) ||
+      nes(info->source) ||
+      nes(info->architecture) ||
+      nes(info->version) ||
+      nes(info->revision) ||
+      info->conffiles ||
+      info->arbs) return 1;
+  return 0;
+}
+
+int informative(struct pkginfo *pkg) {
+  return ((pkg->want != want_unknown && pkg->want != want_purge) ||
+          pkg->eflag != eflagv_ok ||
+          pkg->status != stat_notinstalled ||
+          nes(pkg->section) ||
+          pkg->files ||
+          pkg->priority != pri_unknown);
+}
+
+struct pkginfo *findpackage(const char *name) {
+  struct pkginfo **pointerp, *newpkg;
+
+  pointerp= bins + (hash(name) & (BINS-1));
+  while (*pointerp && strcasecmp((*pointerp)->name,name))
+    pointerp= &(*pointerp)->next;
+  if (*pointerp) return *pointerp;
+
+  newpkg= nfmalloc(sizeof(struct pkginfo));
+  blankpackage(newpkg);
+  newpkg->name= nfstrsave(name);
+  newpkg->next= 0;
+  *pointerp= newpkg;
+  npackages++;
+
+  return newpkg;
+}
+
+int countpackages(void) {
+  return npackages;
+}
+
+struct pkgiterator {
+  struct pkginfo *pigp;
+  int nbinn;
+};
+
+struct pkgiterator *iterpkgstart(void) {
+  struct pkgiterator *i;
+  i= m_malloc(sizeof(struct pkgiterator));
+  i->pigp= 0;
+  i->nbinn= 0;
+  return i;
+}
+
+struct pkginfo *iterpkgnext(struct pkgiterator *i) {
+  struct pkginfo *r;
+  while (!i->pigp) {
+    if (i->nbinn >= BINS) return 0;
+    i->pigp= bins[i->nbinn++];
+  }
+  r= i->pigp; i->pigp= r->next; return r;
+}
+
+void iterpkgend(struct pkgiterator *i) {
+  free(i);
+}
+
+void resetpackages(void) {
+  int i;
+  nffreeall();
+  npackages= 0;
+  for (i=0; i<BINS; i++) bins[i]= 0;
+}
+
+void hashreport(FILE *file) {
+  int i, c;
+  struct pkginfo *pkg;
+  int *freq;
+
+  freq= m_malloc(sizeof(int)*npackages+1);
+  for (i=0; i<=npackages; i++) freq[i]= 0;
+  for (i=0; i<BINS; i++) {
+    for (c=0, pkg= bins[i]; pkg; c++, pkg= pkg->next);
+    fprintf(file,"bin %5d has %7d\n",i,c);
+    freq[c]++;
+  }
+  for (i=npackages; i>0 && freq[i]==0; i--);
+  while (i>=0) { fprintf(file,"size %7d occurs %5d times\n",i,freq[i]); i--; }
+  if (ferror(file)) ohshite("failed write during hashreport");
+}
+
+/*
+ * Test dataset package names were:
+ *
+ * agetty bash bc bdflush biff bin86 binutil binutils bison bsdutils
+ * byacc chfn cron dc dictionaries diff dlltools dpkg e2fsprogs ed
+ * elisp19 elm emacs emacs-nox emacs-x emacs19 file fileutils find
+ * flex fsprogs gas gawk gcc gcc1 gcc2 gdb ghostview ghstview glibcdoc
+ * gnuplot grep groff gs gs_both gs_svga gs_x gsfonts gxditviw gzip
+ * hello hostname idanish ifrench igerman indent inewsinn info inn
+ * ispell kbd kern1148 language ldso less libc libgr libgrdev librl
+ * lilo linuxsrc login lout lpr m4 mailx make man manpages more mount
+ * mtools ncurses netbase netpbm netstd patch perl4 perl5 procps
+ * psutils rcs rdev sed sendmail seyon shar shellutils smail svgalib
+ * syslogd sysvinit tar tcpdump tcsh tex texidoc texinfo textutils
+ * time timezone trn unzip uuencode wenglish wu-ftpd x8514 xaxe xbase
+ * xbdm2 xcomp xcoral xdevel xfig xfnt100 xfnt75 xfntbig xfntscl
+ * xgames xherc xmach32 xmach8 xmono xnet xs3 xsvga xtexstuff xv
+ * xvga16 xxgdb zip
+ */
diff --git a/lib/dbmodify.c b/lib/dbmodify.c
new file mode 100644 (file)
index 0000000..9fdd646
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * dpkg - main program for package management
+ * dbmodify.c - routines for managing dpkg database updates
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+char *statusfile=0, *availablefile=0;
+
+static enum modstatdb_rw cstatus=-1, cflags=0;
+static char *importanttmpfile=0;
+static FILE *importanttmp;
+static int nextupdate;
+static int updateslength;
+static char *updatefnbuf, *updatefnrest;
+static const char *admindir;
+static struct varbuf uvb;
+
+static int ulist_select(const struct dirent *de) {
+  const char *p;
+  int l;
+  for (p= de->d_name, l=0; *p; p++, l++)
+    if (!isdigit(*p)) return 0;
+  if (l > IMPORTANTMAXLEN)
+    ohshit("updates directory contains file `%.250s' whose name is too long "
+           "(length=%d, max=%d)", de->d_name, l, IMPORTANTMAXLEN);
+  if (updateslength == -1) updateslength= l;
+  else if (l != updateslength)
+    ohshit("updates directory contains files with different length names "
+           "(both %d and %d)", l, updateslength);
+  return 1;
+}
+
+static void cleanupdates(void) {
+  struct dirent **cdlist;
+  int cdn, i;
+
+  parsedb(statusfile, pdb_weakclassification, 0,0,0);
+
+  *updatefnrest= 0;
+  updateslength= -1;
+  cdn= scandir(updatefnbuf, &cdlist, &ulist_select, alphasort);
+  if (cdn == -1) ohshite("cannot scan updates directory `%.255s'",updatefnbuf);
+
+  if (cdn) {
+    
+    for (i=0; i<cdn; i++) {
+      strcpy(updatefnrest, cdlist[i]->d_name);
+      parsedb(updatefnbuf, pdb_weakclassification, 0,0,0);
+      if (cstatus < msdbrw_write) free(cdlist[i]);
+    }
+
+    if (cstatus >= msdbrw_write) {
+      writedb(statusfile,0,1);
+    
+      for (i=0; i<cdn; i++) {
+        strcpy(updatefnrest, cdlist[i]->d_name);
+        if (unlink(updatefnbuf))
+          ohshite("failed to remove incorporated update file %.255s",updatefnbuf);
+        free(cdlist[i]);
+      }
+    }
+    
+  }
+  free(cdlist);
+
+  nextupdate= 0;
+}
+
+static void createimptmp(void) {
+  int i;
+  
+  onerr_abort++;
+  
+  importanttmp= fopen(importanttmpfile,"w");
+  if (!importanttmp) ohshite("unable to create %.250s",importanttmpfile);
+  for (i=0; i<512; i++) fputs("#padding\n",importanttmp);
+  if (ferror(importanttmp))
+    ohshite("unable to fill %.250s with padding",importanttmpfile);
+  if (fflush(importanttmp))
+    ohshite("unable flush %.250s after padding",importanttmpfile);
+  if (fseek(importanttmp,0,SEEK_SET))
+    ohshite("unable seek to start of %.250s after padding",importanttmpfile);
+
+  onerr_abort--;
+}
+
+enum modstatdb_rw modstatdb_init(const char *adir, enum modstatdb_rw readwritereq) {
+  static const struct fni { const char *suffix; char **store; } fnis[]= {
+    {   STATUSFILE,                 &statusfile         },
+    {   AVAILFILE,                  &availablefile      },
+    {   UPDATESDIR IMPORTANTTMP,    &importanttmpfile   },
+    {   0                                               }
+  }, *fnip;
+
+  admindir= adir;
+  
+  for (fnip=fnis; fnip->suffix; fnip++) {
+    free(*fnip->store);
+    *fnip->store= m_malloc(strlen(adir)+strlen(fnip->suffix)+2);
+    sprintf(*fnip->store, "%s/%s", adir, fnip->suffix);
+  }
+
+  cflags= readwritereq & msdbrw_flagsmask;
+  readwritereq &= ~msdbrw_flagsmask;
+
+  switch (readwritereq) {
+  case msdbrw_needsuperuser:
+  case msdbrw_needsuperuserlockonly:
+    if (getuid() || geteuid())
+      ohshit("requested operation requires superuser privilege");
+    /* fall through */
+  case msdbrw_write: case msdbrw_writeifposs:
+    if (access(adir,W_OK)) {
+      if (errno != EACCES)
+        ohshite("unable to access dpkg status area");
+      else if (readwritereq == msdbrw_write)
+        ohshit("operation requires read/write access to dpkg status area");
+      cstatus= msdbrw_readonly;
+    } else {
+      lockdatabase(adir);
+      cstatus= (readwritereq == msdbrw_needsuperuserlockonly ?
+                msdbrw_needsuperuserlockonly :
+                msdbrw_write);
+    }
+    break;
+  case msdbrw_readonly:
+    cstatus= msdbrw_readonly; break;
+  default:
+    internerr("unknown readwritereq");
+  }
+
+  updatefnbuf= m_malloc(strlen(adir)+sizeof(UPDATESDIR)+IMPORTANTMAXLEN+5);
+  strcpy(updatefnbuf,adir);
+  strcat(updatefnbuf,"/" UPDATESDIR);
+  updatefnrest= updatefnbuf+strlen(updatefnbuf);
+
+  cleanupdates();
+
+  if (cstatus >= msdbrw_write) {
+    createimptmp();
+    uvb.used= 0;
+    uvb.size= 10240;
+    uvb.buf= m_malloc(uvb.size);
+  }
+
+  if (cstatus != msdbrw_needsuperuserlockonly) {
+    parsedb(statusfile, pdb_weakclassification, 0,0,0);
+    parsedb(statusfile, pdb_recordavailable, 0,0,0);
+    parsedb(availablefile,
+            pdb_recordavailable|pdb_rejectstatus|
+            (cflags & msdbrw_availablepreferversion ? pdb_preferversion : 0),
+            0,0,0);
+  }
+
+  return cstatus;
+}
+
+static void checkpoint(void) {
+  int i;
+
+  assert(cstatus >= msdbrw_write);
+  writedb(statusfile,0,1);
+  
+  for (i=0; i<nextupdate; i++) {
+    sprintf(updatefnrest, IMPORTANTFMT, i);
+    assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); /* or we've made a real mess */
+    if (unlink(updatefnbuf))
+      ohshite("failed to remove my own update file %.255s",updatefnbuf);
+  }
+  nextupdate= 0;
+}
+
+void modstatdb_shutdown(void) {
+  switch (cstatus) {
+  case msdbrw_write:
+    checkpoint();
+    if (!(cflags & msdbrw_availablepreferversion))
+      writedb(availablefile,1,0);
+
+    /* tidy up a bit, but don't worry too much about failure */
+    fclose(importanttmp);
+    strcpy(updatefnrest, IMPORTANTTMP); unlink(updatefnbuf);
+    varbuffree(&uvb);
+    /* fall through */
+  case msdbrw_needsuperuserlockonly:
+    unlockdatabase(admindir);
+  default:
+    break;
+  }
+
+  free(updatefnbuf);
+}
+
+void modstatdb_note(struct pkginfo *pkg) {
+  assert(cstatus >= msdbrw_write);
+
+  onerr_abort++;
+
+  varbufreset(&uvb);
+  varbufrecord(&uvb, pkg, &pkg->installed);
+  if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used)
+    ohshite("unable to write updated status of `%.250s'", pkg->name);
+  if (fflush(importanttmp))
+    ohshite("unable to flush updated status of `%.250s'", pkg->name);
+  if (ftruncate(fileno(importanttmp), uvb.used))
+    ohshite("unable to truncate for updated status of `%.250s'", pkg->name);
+  if (fsync(fileno(importanttmp)))
+    ohshite("unable to fsync updated status of `%.250s'", pkg->name);
+  if (fclose(importanttmp))
+    ohshite("unable to close updated status of `%.250s'", pkg->name);
+  sprintf(updatefnrest, IMPORTANTFMT, nextupdate);
+  if (rename(importanttmpfile, updatefnbuf))
+    ohshite("unable to install updated status of `%.250s'", pkg->name);
+  assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); /* or we've made a real mess */
+
+  nextupdate++;  
+
+  if (nextupdate > MAXUPDATES) checkpoint();
+
+  createimptmp();
+
+  onerr_abort--;
+}
diff --git a/lib/debugmake b/lib/debugmake
new file mode 100755 (executable)
index 0000000..57ac0b1
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -DMDEBUG -O0' LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
diff --git a/lib/dump.c b/lib/dump.c
new file mode 100644 (file)
index 0000000..97d5c43
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dump.c - code to write in-core database to a file
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* fixme: don't write uninteresting packages */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "parsedump.h"
+
+void w_name(struct varbuf *vb,
+            const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+            const struct fieldinfo *fip) {
+  assert(pigp->name);
+  varbufaddstr(vb,"Package: "); varbufaddstr(vb, pigp->name);
+  varbufaddc(vb,'\n');
+}
+
+void w_version(struct varbuf *vb,
+               const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+               const struct fieldinfo *fip) {
+  /* Revision information is printed in version field too. */
+  if ((!pifp->version || !*pifp->version) &&
+      (!pifp->revision || !*pifp->revision)) return;
+  varbufaddstr(vb,"Version: ");
+  varbufaddstr(vb,pifp->version ? pifp->version : "");
+  if (pifp->revision && *pifp->revision) {
+    varbufaddc(vb,'-');
+    varbufaddstr(vb,pifp->revision);
+  }
+  varbufaddc(vb,'\n');
+}
+
+void w_configversion(struct varbuf *vb,
+                     const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                     const struct fieldinfo *fip) {
+  if ((!pigp->configversion || !*pigp->configversion) &&
+      (!pigp->configrevision || !*pigp->configrevision)) return;
+  if (pifp != &pigp->installed) return;
+  if (pigp->status == stat_installed || pigp->status == stat_notinstalled) return;
+  varbufaddstr(vb,"Config-Version: ");
+  varbufaddstr(vb,pigp->configversion ? pigp->configversion : "");
+  if (pigp->configrevision && *pigp->configrevision) {
+    varbufaddc(vb,'-');
+    varbufaddstr(vb,pigp->configrevision);
+  }
+  varbufaddc(vb,'\n');
+}
+
+void w_null(struct varbuf *vb,
+            const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+            const struct fieldinfo *fip) {
+}
+
+void w_section(struct varbuf *vb,
+               const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+               const struct fieldinfo *fip) {
+  const char *value= pigp->section;
+  if (!value || !*value) return;
+  varbufaddstr(vb,"Section: ");
+  varbufaddstr(vb,value);
+  varbufaddc(vb,'\n');
+}
+
+void w_charfield(struct varbuf *vb,
+                 const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                 const struct fieldinfo *fip) {
+  const char *value= pifp->valid ? PKGPFIELD(pifp,fip->integer,char*) : 0;
+  if (!value || !*value) return;
+  varbufaddstr(vb,fip->name); varbufaddstr(vb, ": "); varbufaddstr(vb,value);
+  varbufaddc(vb,'\n');
+}
+
+void w_filecharf(struct varbuf *vb,
+                 const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                 const struct fieldinfo *fip) {
+  struct filedetails *fdp;
+  
+  if (pifp != &pigp->available) return;
+  fdp= pigp->files;
+  if (!fdp || !FILEFFIELD(fdp,fip->integer,char*)) return;
+  varbufaddstr(vb,fip->name); varbufaddc(vb,':');
+  while (fdp) {
+    varbufaddc(vb,' ');
+    varbufaddstr(vb,FILEFFIELD(fdp,fip->integer,char*));
+    fdp= fdp->next;
+  }
+  varbufaddc(vb,'\n');
+}
+
+void w_booleandefno(struct varbuf *vb,
+                    const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                    const struct fieldinfo *fip) {
+  int value= pifp->valid ? PKGPFIELD(pifp,fip->integer,int) : 0;
+  if (!value) return;
+  assert(value==1);
+  varbufaddstr(vb,"Essential: yes\n");
+}
+
+void w_priority(struct varbuf *vb,
+                const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                const struct fieldinfo *fip) {
+  if (pigp->priority == pri_unknown) return;
+  assert(pigp->priority <= pri_unknown);
+  varbufaddstr(vb,"Priority: ");
+  varbufaddstr(vb,
+               pigp->priority == pri_other
+               ? pigp->otherpriority
+               : priorityinfos[pigp->priority].name);
+  varbufaddc(vb,'\n');
+}
+
+void w_status(struct varbuf *vb,
+              const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+              const struct fieldinfo *fip) {
+  if (pifp != &pigp->installed) return;
+  assert(pigp->want <= want_purge &&
+         pigp->eflag <= eflagv_both &&
+         pigp->status <= stat_configfiles);
+  varbufaddstr(vb,"Status: ");
+  varbufaddstr(vb,wantinfos[pigp->want].name); varbufaddc(vb,' ');
+  varbufaddstr(vb,eflaginfos[pigp->eflag].name); varbufaddc(vb,' ');
+  varbufaddstr(vb,statusinfos[pigp->status].name); varbufaddc(vb,'\n');
+}
+
+void varbufdependency(struct varbuf *vb, struct dependency *dep) {
+  struct deppossi *dop;
+  const char *possdel;
+
+  possdel= "";
+  for (dop= dep->list; dop; dop= dop->next) {
+    assert(dop->up == dep);
+    varbufaddstr(vb,possdel); possdel= " | ";
+    varbufaddstr(vb,dop->ed->name);
+    if (dop->verrel != dvr_none) {
+      varbufaddstr(vb," (");
+      switch (dop->verrel) {
+      case dvr_exact: varbufaddc(vb,'='); break;
+      case dvr_laterequal: varbufaddstr(vb,">="); break;
+      case dvr_earlierequal: varbufaddstr(vb,"<="); break;
+      case dvr_laterstrict: varbufaddstr(vb,">>"); break;
+      case dvr_earlierstrict: varbufaddstr(vb,"<<"); break;
+      default: internerr("unknown verrel");
+      }
+      if (!isalnum(dop->version[0])) varbufaddc(vb,' ');
+      varbufaddstr(vb,dop->version);
+      if (dop->revision) { varbufaddc(vb,'-'); varbufaddstr(vb,dop->revision); }
+      varbufaddc(vb,')');
+    }
+  }
+}
+
+void w_dependency(struct varbuf *vb,
+                  const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                  const struct fieldinfo *fip) {
+  char fnbuf[50];
+  const char *depdel;
+  struct dependency *dyp;
+
+  if (!pifp->valid) return;
+  sprintf(fnbuf,"%s: ",fip->name); depdel= fnbuf;
+  for (dyp= pifp->depends; dyp; dyp= dyp->next) {
+    if (dyp->type != fip->integer) continue;
+    assert(dyp->up == pigp);
+    varbufaddstr(vb,depdel); depdel= ", ";
+    varbufdependency(vb,dyp);
+  }
+  if (depdel != fnbuf) varbufaddc(vb,'\n');
+}
+
+void w_conffiles(struct varbuf *vb,
+                 const struct pkginfo *pigp, const struct pkginfoperfile *pifp,
+                 const struct fieldinfo *fip) {
+  struct conffile *i;
+
+  if (!pifp->valid || !pifp->conffiles || pifp == &pigp->available) return;
+  varbufaddstr(vb,"Conffiles:\n");
+  for (i=pifp->conffiles; i; i= i->next) {
+    varbufaddc(vb,' '); varbufaddstr(vb,i->name); varbufaddc(vb,' ');
+    varbufaddstr(vb,i->hash); varbufaddc(vb,'\n');
+  }
+}
+
+void varbufrecord(struct varbuf *vb,
+                  const struct pkginfo *pigp, const struct pkginfoperfile *pifp) {
+  const struct fieldinfo *fip;
+  const struct arbitraryfield *afp;
+
+  for (fip= fieldinfos; fip->name; fip++) {
+    fip->wcall(vb,pigp,pifp,fip);
+  }
+  if (pifp->valid) {
+    for (afp= pifp->arbs; afp; afp= afp->next) {
+      varbufaddstr(vb,afp->name); varbufaddstr(vb,": ");
+      varbufaddstr(vb,afp->value); varbufaddc(vb,'\n');
+    }
+  }
+}
+
+void writerecord(FILE *file, const char *filename,
+                 const struct pkginfo *pigp, const struct pkginfoperfile *pifp) {
+  struct varbuf vb;
+
+  varbufinit(&vb);
+  varbufrecord(&vb,pigp,pifp);
+  varbufaddc(&vb,'\0');
+  if (!fputs(vb.buf,file))
+    ohshite("failed to write details of `%.50s' to `%.250s'", pigp->name, filename);
+}
+
+void writedb(const char *filename, int available, int mustsync) {
+  static char writebuf[8192];
+  
+  struct pkgiterator *it;
+  struct pkginfo *pigp;
+  char *oldfn, *newfn;
+  const char *which;
+  FILE *file;
+  struct varbuf vb;
+
+  which= available ? "available" : "status";
+  oldfn= m_malloc(strlen(filename)+sizeof(OLDDBEXT));
+  strcpy(oldfn,filename); strcat(oldfn,OLDDBEXT);
+  newfn= m_malloc(strlen(filename)+sizeof(NEWDBEXT));
+  strcpy(newfn,filename); strcat(newfn,NEWDBEXT);
+  varbufinit(&vb);
+
+  file= fopen(newfn,"w");
+  if (!file) ohshite("failed to open `%s' for writing %s information",filename,which);
+  
+  if (setvbuf(file,writebuf,_IOFBF,sizeof(writebuf)))
+    ohshite("unable to set buffering on status file");
+
+  it= iterpkgstart();
+  while ((pigp= iterpkgnext(it)) != 0) {
+    if (!(informative(pigp) ||
+          informativeperfile(&pigp->available) ||
+          informativeperfile(&pigp->installed)))
+      /* Don't dump records which have no useful content. */
+      continue;
+    varbufrecord(&vb, pigp, available ? &pigp->available : &pigp->installed);
+    varbufaddc(&vb,'\n'); varbufaddc(&vb,0);
+    if (!fputs(vb.buf,file))
+      ohshite("failed to write %s record about `%.50s' to `%.250s'",
+              which, pigp->name, filename);
+    varbufreset(&vb);      
+  }
+  varbuffree(&vb);
+  if (mustsync) {
+    if (fflush(file))
+      ohshite("failed to flush %s information to `%.250s'", which, filename);
+    if (fsync(fileno(file)))
+      ohshite("failed to fsync %s information to `%.250s'", which, filename);
+  }
+  if (fclose(file)) ohshite("failed to close `%.250s' after writing %s information",
+                            filename, which);
+  unlink(oldfn);
+  if (link(filename,oldfn) && errno != ENOENT)
+    ohshite("failed to link `%.250s' to `%.250s' for backup of %s info",
+            filename, oldfn, which);
+  if (rename(newfn,filename))
+    ohshite("failed to install `%.250s' as `%.250s' containing %s info",
+            newfn, filename, which);
+}
diff --git a/lib/ehandle.c b/lib/ehandle.c
new file mode 100644 (file)
index 0000000..f0843b9
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * ehandle.c - error handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+static const char *errmsg; /* points to errmsgbuf or malloc'd */
+static char errmsgbuf[4096];
+/* 6x255 for inserted strings (%.255s &c in fmt; also %s with limited length arg)
+ * 1x255 for constant text
+ * 1x255 for strerror()
+ * same again just in case.
+ */
+
+#define NCALLS 2
+
+struct cleanupentry {
+  struct cleanupentry *next;
+  struct {
+    int mask;
+    void (*call)(int argc, void **argv);
+  } calls[NCALLS];
+  int cpmask, cpvalue;
+  int argc;
+  void *argv[1];
+};         
+
+struct errorcontext {
+  struct errorcontext *next;
+  jmp_buf *jbufp;
+  struct cleanupentry *cleanups;
+  void (*printerror)(const char *emsg, const char *contextstring);
+  const char *contextstring;
+};
+
+static struct errorcontext *volatile econtext= 0;
+static struct { struct cleanupentry ce; void *args[20]; } emergency;
+
+void set_error_display(void (*printerror)(const char *, const char *),
+                       const char *contextstring) {
+  assert(econtext);
+  econtext->printerror= printerror;
+  econtext->contextstring= contextstring;
+}
+
+void push_error_handler(jmp_buf *jbufp,
+                        void (*printerror)(const char *, const char *),
+                        const char *contextstring) {
+  struct errorcontext *necp;
+  necp= malloc(sizeof(struct errorcontext));
+  if (!necp) {
+    int e= errno;
+    strcpy(errmsgbuf, "out of memory pushing error handler: ");
+    strcat(errmsgbuf, strerror(e));  errmsg= errmsgbuf;
+    if (econtext) longjmp(*econtext->jbufp,1);
+    fprintf(stderr, "%s: %s\n", thisname, errmsgbuf); exit(2);
+  }
+  necp->next= econtext;
+  necp->jbufp= jbufp;
+  necp->cleanups= 0;
+  necp->printerror= printerror;
+  necp->contextstring= contextstring;
+  econtext= necp;
+  onerr_abort= 0;
+}
+
+static void print_error_cleanup(const char *emsg, const char *contextstring) {
+  fprintf(stderr, "%s: error while cleaning up:\n %s\n",thisname,emsg);
+}
+
+static void run_cleanups(struct errorcontext *econ, int flagsetin) {
+  static volatile int preventrecurse= 0;
+  struct cleanupentry *volatile cep;
+  struct cleanupentry *ncep;
+  struct errorcontext recurserr, *oldecontext;
+  jmp_buf recurejbuf;
+  volatile int i, flagset;
+
+  if (econ->printerror) econ->printerror(errmsg,econ->contextstring);
+     
+  if (++preventrecurse > 3) {
+    onerr_abort++;
+    fprintf(stderr, DPKG ": too many nested errors during error recovery !!\n");
+    flagset= 0;
+  } else {
+    flagset= flagsetin;
+  }
+  cep= econ->cleanups;
+  oldecontext= econtext;
+  while (cep) {
+    for (i=0; i<NCALLS; i++) {
+      if (cep->calls[i].call && cep->calls[i].mask & flagset) {
+        if (setjmp(recurejbuf)) {
+          run_cleanups(&recurserr, ehflag_bombout | ehflag_recursiveerror);
+        } else {
+          recurserr.jbufp= &recurejbuf;
+          recurserr.cleanups= 0;
+          recurserr.next= 0;
+          recurserr.printerror= print_error_cleanup;
+          recurserr.contextstring= 0;
+          econtext= &recurserr;
+          cep->calls[i].call(cep->argc,cep->argv);
+        }
+        econtext= oldecontext;
+      }
+    }
+    ncep= cep->next;
+    if (cep != &emergency.ce) free(cep);
+    cep= ncep;
+  }
+  preventrecurse--;
+}
+
+void error_unwind(int flagset) {
+  struct cleanupentry *cep;
+  struct errorcontext *tecp;
+
+  tecp= econtext;
+  cep= tecp->cleanups;
+  econtext= tecp->next;
+  run_cleanups(tecp,flagset);
+  free(tecp);
+}
+
+void push_checkpoint(int mask, int value) {
+  /* This will arrange that when error_unwind() is called,
+   * all previous cleanups will be executed with
+   *  flagset= (original_flagset & mask) | value
+   * where original_flagset is the argument to error_unwind
+   * (as modified by any checkpoint which was pushed later).
+   */
+  struct cleanupentry *cep;
+  int i;
+  
+  cep= m_malloc(sizeof(struct cleanupentry) + sizeof(char*));
+  for (i=0; i<NCALLS; i++) { cep->calls[i].call=0; cep->calls[i].mask=0; }
+  cep->cpmask= mask; cep->cpvalue= value;
+  cep->argc= 0; cep->argv[0]= 0;
+  cep->next= econtext->cleanups;
+  econtext->cleanups= cep;
+}
+
+void push_cleanup(void (*call1)(int argc, void **argv), int mask1,
+                  void (*call2)(int argc, void **argv), int mask2,
+                  int nargs, ...) {
+  struct cleanupentry *cep;
+  void **args;
+  int e;
+  va_list al;
+
+  onerr_abort++;
+  
+  cep= malloc(sizeof(struct cleanupentry) + sizeof(char*)*(nargs+1));
+  if (!cep) {
+    if (nargs > sizeof(emergency.args)/sizeof(void*))
+      ohshite("out of memory for new cleanup entry with many arguments");
+    e= errno; cep= &emergency.ce;
+  }
+  cep->calls[0].call= call1; cep->calls[0].mask= mask1;
+  cep->calls[1].call= call2; cep->calls[1].mask= mask2;
+  cep->cpmask=~0; cep->cpvalue=0; cep->argc= nargs;
+  va_start(al,nargs);
+  args= cep->argv; while (nargs-- >0) *args++= va_arg(al,void*);
+  *args++= 0;
+  va_end(al);
+  cep->next= econtext->cleanups;
+  econtext->cleanups= cep;
+  if (cep == &emergency.ce) { e= errno; ohshite("out of memory for new cleanup entry"); }
+
+  onerr_abort--;
+}
+
+void pop_cleanup(int flagset) {
+  struct cleanupentry *cep;
+  int i;
+
+  cep= econtext->cleanups;
+  econtext->cleanups= cep->next;
+  for (i=0; i<NCALLS; i++) {
+    if (cep->calls[i].call && cep->calls[i].mask & flagset)
+      cep->calls[i].call(cep->argc,cep->argv);
+    flagset &= cep->cpmask;
+    flagset |= cep->cpvalue;
+  }
+  if (cep != &emergency.ce) free(cep);
+}
+
+void ohshit(const char *fmt, ...) {
+  va_list al;
+  va_start(al,fmt);
+  vsprintf(errmsgbuf,fmt,al);
+  va_end(al);
+  errmsg= errmsgbuf;
+  longjmp(*econtext->jbufp,1);
+}
+
+void print_error_fatal(const char *emsg, const char *contextstring) {
+  fprintf(stderr, "%s: %s\n",thisname,emsg);
+}
+
+void ohshitvb(struct varbuf *vb) {
+  char *m;
+  varbufaddc(vb,0);
+  m= m_malloc(strlen(vb->buf));
+  strcpy(m,vb->buf);
+  errmsg= m;
+  longjmp(*econtext->jbufp,1);
+}
+
+void ohshitv(const char *fmt, va_list al) {
+  vsprintf(errmsgbuf,fmt,al);
+  errmsg= errmsgbuf;
+  longjmp(*econtext->jbufp,1);
+}
+
+void ohshite(const char *fmt, ...) {
+  int e;
+  va_list al;
+
+  e=errno;
+  va_start(al,fmt);
+  vsprintf(errmsgbuf,fmt,al);
+  va_end(al);
+
+  strcat(errmsgbuf,": ");
+  strcat(errmsgbuf,strerror(e));
+  errmsg= errmsgbuf; 
+  longjmp(*econtext->jbufp,1);
+}
+
+void badusage(const char *fmt, ...) {
+  va_list al;
+  va_start(al,fmt);
+  vsprintf(errmsgbuf,fmt,al);
+  va_end(al);
+  strcat(errmsgbuf,"\n\n");
+  strcat(errmsgbuf,printforhelp);
+  errmsg= errmsgbuf; 
+  longjmp(*econtext->jbufp,1);
+}
+
+void werr(const char *fn) {
+  ohshite("error writing `%.250s'",fn);
+}
+
+void do_internerr(const char *string, int line, const char *file) {
+  fprintf(stderr,"%s:%d: internal error `%s'\n",file,line,string);
+  abort();
+}
diff --git a/lib/fields.c b/lib/fields.c
new file mode 100644 (file)
index 0000000..9066c04
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * fields.c - parsing of all the different fields, when reading in
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "parsedump.h"
+
+static int convert_string(const char *filename, int lno, const char *what, int otherwise,
+                          FILE *warnto, int *warncount, const struct pkginfo *pigp,
+                          const char *startp, const struct namevalue *nvip,
+                          const char **endpp) {
+  const char *ep;
+  int c, l;
+
+  ep= startp;
+  if (!*ep) parseerr(0,filename,lno, warnto,warncount,pigp,0, "%s is missing",what);
+  while ((c= *ep) && !isspace(c)) ep++;
+  l= (int)(ep-startp);
+  while (nvip->name && (strncasecmp(nvip->name,startp,l) || nvip->name[l])) nvip++;
+  if (!nvip->name) {
+    if (otherwise != -1) return otherwise;
+    parseerr(0,filename,lno, warnto,warncount,pigp,0, "`%.*s' is not allowed for %s",
+             l > 50 ? 50 : l, startp, what);
+  }
+  while (isspace(c)) c= *++ep;
+  if (c && !endpp)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0, "junk after %s",what);
+  if (endpp) *endpp= ep;
+  return nvip->value;
+}
+
+void f_name(struct pkginfo *pigp, struct pkginfoperfile *pifp, enum parsedbflags flags,
+            const char *filename, int lno, FILE *warnto, int *warncount,
+            const char *value, const struct fieldinfo *fip) {
+  const char *e;
+  if ((e= illegal_packagename(value,0)) != 0)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0, "invalid package name (%.250s)",e);
+  pigp->name= nfstrsave(value);
+  findpackage(value); /* We discard the value from findpackage, but calling it
+                       * forces an entry in the hash table to be made if it isn't
+                       * already.  This is so that we don't reorder the file
+                       * unnecessarily (doing so is bad for debugging).
+                       */
+}
+
+void f_filecharf(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                 enum parsedbflags flags,
+                 const char *filename, int lno, FILE *warnto, int *warncount,
+                 const char *value, const struct fieldinfo *fip) {
+  struct filedetails *fdp, **fdpp;
+  char *cpos, *space;
+  int allowextend;
+
+  if (!*value)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0,
+             "empty file details field `%s'",fip->name);
+  if (!(flags & pdb_recordavailable))
+    parseerr(0,filename,lno, warnto,warncount,pigp,0,
+             "file details field `%s' not allowed in status file",fip->name);
+  allowextend= !pigp->files;
+  fdpp= &pigp->files;
+  cpos= nfstrsave(value);
+  while (*cpos) {
+    space= cpos; while (*space && !isspace(*space)) space++;
+    if (*space) *space++= 0;
+    fdp= *fdpp;
+    if (!fdp) {
+      if (!allowextend)
+        parseerr(0,filename,lno, warnto,warncount,pigp,0, "too many values "
+                 "in file details field `%s' (compared to others)",fip->name);
+      fdp= nfmalloc(sizeof(struct filedetails));
+      fdp->next= 0;
+      fdp->name= fdp->msdosname= fdp->size= fdp->md5sum= 0;
+      *fdpp= fdp;
+    }
+    FILEFFIELD(fdp,fip->integer,char*)= cpos;
+    fdpp= &fdp->next;
+    while (*space && isspace(*space)) space++;
+    cpos= space;
+  }
+  if (*fdpp)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0, "too few values "
+             "in file details field `%s' (compared to others)",fip->name);
+}
+
+void f_charfield(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                 enum parsedbflags flags,
+                 const char *filename, int lno, FILE *warnto, int *warncount,
+                 const char *value, const struct fieldinfo *fip) {
+  if (*value) PKGPFIELD(pifp,fip->integer,char*)= nfstrsave(value);
+}
+
+void f_boolean(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+               enum parsedbflags flags,
+               const char *filename, int lno, FILE *warnto, int *warncount,
+               const char *value, const struct fieldinfo *fip) {
+  pifp->essential=
+    *value ? convert_string(filename,lno,"yes/no in `essential' field", -1,
+                            warnto,warncount,pigp,
+                            value,booleaninfos,0)
+           : 0;
+}
+
+void f_section(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+               enum parsedbflags flags,
+               const char *filename, int lno, FILE *warnto, int *warncount,
+               const char *value, const struct fieldinfo *fip) {
+  if (!*value) return;
+  pigp->section= nfstrsave(value);
+}
+
+void f_priority(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                enum parsedbflags flags,
+                const char *filename, int lno, FILE *warnto, int *warncount,
+                const char *value, const struct fieldinfo *fip) {
+  if (!*value) return;
+  pigp->priority= convert_string(filename,lno,"word in `priority' field", pri_other,
+                             warnto,warncount,pigp,
+                             value,priorityinfos,0);
+  if (pigp->priority == pri_other) pigp->otherpriority= nfstrsave(value);
+}
+
+void f_status(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+              enum parsedbflags flags,
+              const char *filename, int lno, FILE *warnto, int *warncount,
+              const char *value, const struct fieldinfo *fip) {
+  const char *ep;
+
+  if (flags & pdb_rejectstatus)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0,
+             "value for `status' field not allowed in this context");
+  if (flags & pdb_recordavailable) return;
+  
+  pigp->want= convert_string(filename,lno,"first (want) word in `status' field", -1,
+                             warnto,warncount,pigp, value,wantinfos,&ep);
+  pigp->eflag= convert_string(filename,lno,"second (error) word in `status' field", -1,
+                              warnto,warncount,pigp, ep,eflaginfos,&ep);
+  pigp->status= convert_string(filename,lno,"third (status) word in `status' field", -1,
+                               warnto,warncount,pigp, ep,statusinfos,0);
+}
+
+void f_configversion(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                     enum parsedbflags flags,
+                     const char *filename, int lno, FILE *warnto, int *warncount,
+                     const char *value, const struct fieldinfo *fip) {
+  char *mycopy, *hyphen;
+
+  if (flags & pdb_rejectstatus)
+    parseerr(0,filename,lno, warnto,warncount,pigp,0,
+             "value for `config-version' field not allowed in this context");
+  if (flags & pdb_recordavailable) return;
+
+  mycopy= nfstrsave(value);
+  hyphen= strrchr(mycopy,'-');
+  if (hyphen) *hyphen++= 0;
+
+  pigp->configversion= mycopy;
+  pigp->configrevision= hyphen ? hyphen : nfstrsave("");
+}
+
+void f_conffiles(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                 enum parsedbflags flags,
+                 const char *filename, int lno, FILE *warnto, int *warncount,
+                 const char *value, const struct fieldinfo *fip) {
+  struct conffile **lastp, *newlink;
+  const char *endent, *endfn;
+  int c, namelen, hashlen;
+  
+  lastp= &pifp->conffiles;
+  while (*value) {
+    c= *value++;
+    if (c == '\n') continue;
+    if (c != ' ') parseerr(0,filename,lno, warnto,warncount,pigp,0, "value for"
+                           " `conffiles' has line starting with non-space `%c'", c);
+    for (endent= value; (c= *endent)!=0 && c != '\n'; endent++);
+    for (endfn= endent; *endfn != ' '; endfn--);
+    if (endfn <= value+1 || endfn >= endent-1)
+      parseerr(0,filename,lno, warnto,warncount,pigp,0,
+               "value for `conffiles' has malformatted line `%.*s'",
+               (int)(endent-value > 250 ? 250 : endent-value), value);
+    newlink= nfmalloc(sizeof(struct conffile));
+    value= skip_slash_dotslash(value);
+    namelen= (int)(endfn-value);
+    if (namelen <= 0) parseerr(0,filename,lno, warnto,warncount,pigp,0,
+                               "root or null directory is listed as a conffile");
+    newlink->name= nfmalloc(namelen+2);
+    newlink->name[0]= '/';
+    memcpy(newlink->name+1,value,namelen);
+    newlink->name[namelen+1]= 0;
+    hashlen= (int)(endent-endfn)-1; newlink->hash= nfmalloc(hashlen+1);
+    memcpy(newlink->hash,endfn+1,hashlen); newlink->hash[hashlen]= 0;
+    newlink->next =0;
+    *lastp= newlink;
+    lastp= &newlink->next;
+    value= endent;
+  }
+}
+
+void f_dependency(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                  enum parsedbflags flags,
+                  const char *filename, int lno, FILE *warnto, int *warncount,
+                  const char *value, const struct fieldinfo *fip) {
+  char *q, c1, c2;
+  const char *p, *emsg;
+  struct varbuf depname, version;
+  struct dependency *dyp, **ldypp;
+  struct deppossi *dop, **ldopp;
+
+  if (!*value) return; /* empty fields are ignored */
+  varbufinit(&depname); varbufinit(&version);
+  p= value;
+  ldypp= &pifp->depends; while (*ldypp) ldypp= &(*ldypp)->next;
+  for (;;) { /* loop creating new struct dependency's */
+    dyp= nfmalloc(sizeof(struct dependency));
+    dyp->up= 0; /* Set this to zero for now, as we don't know what our real
+                 * struct pkginfo address (in the database) is going to be yet.
+                 */
+    dyp->next= 0; *ldypp= dyp; ldypp= &dyp->next;
+    dyp->list= 0; ldopp= &dyp->list;
+    dyp->type= fip->integer;
+    for (;;) { /* loop creating new struct deppossi's */
+      varbufreset(&depname);
+      while (*p && !isspace(*p) && *p != '(' && *p != ',' && *p != '|') {
+        varbufaddc(&depname,*p); p++;
+      }
+      varbufaddc(&depname,0);
+      if (!*depname.buf)
+        parseerr(0,filename,lno, warnto,warncount,pigp,0, "`%s' field, missing"
+                 " package name, or garbage where package name expected", fip->name);
+      emsg= illegal_packagename(depname.buf,0);
+      if (emsg) parseerr(0,filename,lno, warnto,warncount,pigp,0, "`%s' field,"
+                         " invalid package name `%.255s': %s",
+                         fip->name, depname.buf, emsg);
+      dop= nfmalloc(sizeof(struct deppossi));
+      dop->up= dyp;
+      dop->ed= findpackage(depname.buf);
+      dop->next= 0; *ldopp= dop; ldopp= &dop->next;
+      dop->nextrev= 0; /* Don't link this (which is after all only `newpig' from
+      dop->backrev= 0;  * the main parsing loop in parsedb) into the depended on
+                        * packages' lists yet.  This will be done later when we
+                        * install this (in parse.c).  For the moment we do the
+                        * `forward' links in deppossi (`ed') only, and the backward
+                        * links from the depended on packages to dop are left undone.
+                        */
+      dop->cyclebreak= 0;
+      while (isspace(*p)) p++;
+      if (*p == '(') {
+        varbufreset(&version);
+        p++; while (isspace(*p)) p++;
+        c1= *p;
+        if (c1 == '<' || c1 == '>') {
+          c2= *++p;
+          dop->verrel= (c1 == '<') ? dvrf_earlier : dvrf_later;
+          if (c2 == '=') {
+            dop->verrel |= (dvrf_orequal | dvrf_builtup);
+            p++;
+          } else if (c2 == c1) {
+            dop->verrel |= (dvrf_strict | dvrf_builtup);
+            p++;
+          } else if (c2 == '<' || c2 == '>') {
+            parseerr(0,filename,lno, warnto,warncount,pigp,0,
+                    "`%s' field, reference to `%.255s':\n"
+                    " bad version relationship %c%c",
+                    fip->name,depname.buf,c1,c2);
+            dop->verrel= dvr_none;
+          } else {
+            parseerr(0,filename,lno, warnto,warncount,pigp,1,
+                     "`%s' field, reference to `%.255s':\n"
+                     " `%c' is obsolete, use `%c=' or `%c%c' instead",
+                     fip->name,depname.buf,c1,c1,c1,c1);
+            dop->verrel |= (dvrf_orequal | dvrf_builtup);
+          }
+        } else if (c1 == '=') {
+          dop->verrel= dvr_exact;
+          p++;
+        } else {
+          parseerr(0,filename,lno, warnto,warncount,pigp,1,
+                   "`%s' field, reference to `%.255s':\n"
+                   " implicit exact match on version number, suggest using `=' instead",
+                   fip->name,depname.buf);
+          dop->verrel= dvr_exact;
+        }
+        if (!isspace(*p) && !isalnum(*p)) {
+          parseerr(0,filename,lno, warnto,warncount,pigp,1,
+                   "`%s' field, reference to `%.255s':\n"
+                   " version value starts with non-alphanumeric, suggest adding a space",
+                   fip->name,depname.buf);
+        }
+        while (isspace(*p)) p++;
+        while (*p && *p != ')' && *p != '(') {
+          if (!isspace(*p)) varbufaddc(&version,*p);
+          p++;
+        }
+        if (*p == '(') parseerr(0,filename,lno, warnto,warncount,pigp,0,
+                                "`%s' field, reference to `%.255s'"
+                                " version contains (", fip->name, depname.buf);
+        else if (*p == 0) parseerr(0,filename,lno, warnto,warncount,pigp,0,
+                                   "`%s' field, reference to `%.255s'"
+                                   "version unterminated", fip->name, depname.buf);
+        varbufaddc(&version,0);
+        q= strrchr(version.buf,'-');
+        if (q) {
+          *q++= 0;
+          dop->revision= nfstrsave(q);
+        } else {
+          dop->revision= 0;
+        }
+        dop->version= nfstrsave(version.buf);
+        p++; while (isspace(*p)) p++;
+      } else {
+        dop->verrel= dvr_none;
+        dop->revision= dop->version= 0;
+      }
+      if (!*p || *p == ',') break;
+      if (*p != '|')
+        parseerr(0,filename,lno, warnto,warncount,pigp,0, "`%s' field, syntax"
+                 " error after reference to package `%.255s'",
+                 fip->name, dop->ed->name);
+      if (fip->integer == dep_conflicts ||
+          fip->integer == dep_provides ||
+          fip->integer == dep_replaces)
+        parseerr(0,filename,lno, warnto,warncount,pigp,0,
+                 "alternatives (`|') not allowed in %s field",
+                 fip->name);
+      p++; while (isspace(*p)) p++;
+    }
+    if (!*p) break;
+    p++; while (isspace(*p)) p++;
+  }
+}
+
diff --git a/lib/lock.c b/lib/lock.c
new file mode 100644 (file)
index 0000000..e0af62a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * lock.c - packages database locking
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/file.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+static char *dblockfile= 0;
+static int dblockfd= -1;
+
+static void cu_unlockdb(int argc, void **argv) {
+  struct flock fl;
+  assert(dblockfile);
+  assert(dblockfd >= 0);
+  fl.l_type= F_UNLCK;
+  fl.l_whence= SEEK_SET;
+  fl.l_start= 0;
+  fl.l_len= 1;
+  if (fcntl(dblockfd,F_SETLK,&fl) == -1)
+    ohshite("unable to unlock dpkg status database");
+}
+
+void unlockdatabase(const char *admindir) {
+  pop_cleanup(ehflag_normaltidy); /* calls cu_unlockdb */
+}
+
+void lockdatabase(const char *admindir) {
+  int n;
+  struct flock fl;
+  
+  if (!dblockfile) {
+    n= strlen(admindir);
+    dblockfile= m_malloc(n+sizeof(LOCKFILE)+2);
+    strcpy(dblockfile,admindir);
+    strcpy(dblockfile+n, "/" LOCKFILE);
+  }
+  if (dblockfd == -1) {
+    dblockfd= open(dblockfile, O_RDWR|O_CREAT|O_TRUNC, 0660);
+    if (dblockfd == -1) {
+      if (errno == EPERM)
+        ohshit("you do not have permission to lock the dpkg status database");
+      ohshite("unable to open/create status database lockfile");
+    }
+  }
+  fl.l_type= F_WRLCK;
+  fl.l_whence= SEEK_SET;
+  fl.l_start= 0;
+  fl.l_len= 1;
+  if (fcntl(dblockfd,F_SETLK,&fl) == -1) {
+    if (errno == EWOULDBLOCK || errno == EAGAIN)
+      ohshit("status database area is locked - another dpkg/dselect is running");
+    ohshite("unable to lock dpkg status database");
+  }
+  push_cleanup(cu_unlockdb,~0, 0,0, 0);
+}
diff --git a/lib/mlib.c b/lib/mlib.c
new file mode 100644 (file)
index 0000000..5fee2a4
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * mlib.c - `must' library: routines will succeed or longjmp
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "dpkg.h"
+
+/* Incremented when we do some kind of generally necessary operation, so that
+ * loops &c know to quit if we take an error exit.  Decremented again afterwards.
+ */
+volatile int onerr_abort= 0;
+
+void *m_malloc(size_t amount) {
+#ifdef MDEBUG
+  unsigned short *r2, x;
+#endif
+  void *r;
+  
+  onerr_abort++;
+  r= malloc(amount);
+  if (!r) ohshite("malloc failed (%ld bytes)",(long)amount);
+  onerr_abort--;
+  
+#ifdef MDEBUG
+  r2= r; x= (unsigned short)amount ^ 0xf000;
+  while (amount >= 2) { *r2++= x; amount -= 2; }
+#endif
+  return r;
+}
+
+void *m_realloc(void *r, size_t amount) {
+  onerr_abort++;
+  r= realloc(r,amount);
+  if (!r) ohshite("realloc failed (%ld bytes)",(long)amount);
+  onerr_abort--;
+
+  return r;
+}
+
+static void print_error_forked(const char *emsg, const char *contextstring) {
+  fprintf(stderr, "%s (subprocess): %s\n", thisname, emsg);
+}
+
+static void cu_m_fork(int argc, void **argv) {
+  exit(2);
+  /* Don't do the other cleanups, because they'll be done by/in the parent
+   * process.
+   */
+}
+
+int m_fork(void) {
+  pid_t r;
+  r= fork();
+  if (r == -1) { onerr_abort++; ohshite("fork failed"); }
+  if (r > 0) return r;
+  push_cleanup(cu_m_fork,~0, 0,0, 0);
+  set_error_display(print_error_forked,0);
+  return r;
+}
+
+void m_dup2(int oldfd, int newfd) {
+  const char *const stdstrings[]= { "in", "out", "err" };
+  
+  if (dup2(oldfd,newfd) == newfd) return;
+
+  onerr_abort++;
+  if (newfd < 3) ohshite("failed to dup for std%s",stdstrings[newfd]);
+  ohshite("failed to dup for fd %d",newfd);
+}
+
+void m_pipe(int *fds) {
+  if (!pipe(fds)) return;
+  onerr_abort++;
+  ohshite("failed to create pipe");
+}
+
+void checksubprocerr(int status, const char *description, int sigpipeok) {
+  int n;
+  if (WIFEXITED(status)) {
+    n= WEXITSTATUS(status); if (!n) return;
+    ohshit("subprocess %s returned error exit status %d",description,n);
+  } else if (WIFSIGNALED(status)) {
+    n= WTERMSIG(status); if (!n || (sigpipeok && n==SIGPIPE)) return;
+    ohshit("subprocess %s killed by signal (%s)%s",
+           description, strsignal(n), WCOREDUMP(status) ? ", core dumped" : "");
+  } else {
+    ohshit("subprocess %s failed with wait status code %d",description,status);
+  }
+}
+
+void waitsubproc(pid_t pid, const char *description, int sigpipeok) {
+  pid_t r;
+  int status;
+
+  while ((r= waitpid(pid,&status,0)) == -1 && errno == EINTR);
+  if (r != pid) { onerr_abort++; ohshite("wait for %s failed",description); }
+  checksubprocerr(status,description,sigpipeok);
+}
diff --git a/lib/myopt.c b/lib/myopt.c
new file mode 100644 (file)
index 0000000..b3c2167
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.c - my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+
+#include "config.h"
+#include "myopt.h"
+#include "dpkg.h"
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos) {
+  const struct cmdinfo *cip;
+  const char *p, *value;
+  int l;
+
+  ++(*argvp);
+  while ((p= **argvp) && *p == '-') {
+    ++(*argvp);
+    if (!strcmp(p,"--")) break;
+    if (*++p == '-') {
+      ++p; value=0;
+      for (cip= cmdinfos;
+           cip->olong || cip->oshort;
+           cip++) {
+        if (!cip->olong) continue;
+        if (!strcmp(p,cip->olong)) break;
+        l= strlen(cip->olong);
+        if (!strncmp(p,cip->olong,l) &&
+            (p[l]== ((cip->takesvalue==2) ? '-' : '='))) { value=p+l+1; break; }
+      }
+      if (!cip->olong) badusage("unknown option --%s",p);
+      if (cip->takesvalue) {
+        if (!value) {
+          value= *(*argvp)++;
+          if (!value) badusage("--%s option takes a value",cip->olong);
+        }
+        if (cip->call) cip->call(cip,value);
+        else *cip->sassignto= value;
+      } else {
+        if (value) badusage("--%s option does not take a value",cip->olong);
+        if (cip->call) cip->call(cip,0);
+        else *cip->iassignto= cip->arg;
+      }
+    } else {
+      while (*p) {
+        for (cip= cmdinfos; (cip->olong || cip->oshort) && *p != cip->oshort; cip++);
+        if (!cip->oshort) badusage("unknown option -%c",*p);
+        p++;
+        if (cip->takesvalue) {
+          if (!*p) {
+            value= *(*argvp)++;
+            if (!value) badusage("-%c option takes a value",cip->oshort);
+          } else {
+            value= p; p="";
+            if (*value == '=') value++;
+          }
+          if (cip->call) cip->call(cip,value);
+          else *cip->sassignto= value;
+        } else {
+          if (*p == '=') badusage("-%c option does not take a value",cip->oshort);
+          if (cip->call) cip->call(cip,0);
+          else *cip->iassignto= cip->arg;
+        }
+      }
+    }
+  }
+}
diff --git a/lib/nfmalloc.c b/lib/nfmalloc.c
new file mode 100644 (file)
index 0000000..225e698
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * nfmalloc.c - non-freeing malloc, used for in-core database
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+#define ABLOCKSIZE 65536
+#define UNIQUE      4096
+
+union maxalign {
+  long l; long double d;
+  void *pv; char *pc; union maxalign *ps; void (*pf)(void);
+};
+
+static unsigned char *playground= 0;
+static long remaining= 0;
+static struct piece { struct piece *next; union maxalign space; } *pieces= 0;
+
+void nffreeall(void) {
+  struct piece *a,*b;
+  for (a=pieces; a; a=b) { b=a->next; free(a); }
+  pieces= 0; remaining= 0;
+}
+
+static void *nfmalloc_sysmalloc(size_t size) {
+  struct piece *alc;
+  alc= m_malloc(size + sizeof(struct piece));
+  alc->next= pieces; pieces= alc;
+  return &alc->space;
+}
+
+#ifndef MDEBUG
+void *nfmalloc(size_t size) {
+#else
+static void *nfmalloc_r(size_t size) {
+#endif
+  const size_t alignment= sizeof(union maxalign);
+
+  size -= (size + alignment-1) % alignment;
+  size += alignment-1;
+  if (size > UNIQUE) return nfmalloc_sysmalloc(size);
+  remaining -= size;
+  if (remaining > 0) return playground -= size;
+  playground= (unsigned char*)nfmalloc_sysmalloc(ABLOCKSIZE) + ABLOCKSIZE - size;
+  remaining= ABLOCKSIZE-size;
+  return playground;
+}
+
+#ifdef MDEBUG
+/* If we haven't switched off debugging we wrap nfmalloc in something
+ * that fills the space with junk that may tell us what happened if
+ * we dereference a wild pointer.  It's better than leaving it full of
+ * nulls, anyway.
+ */
+void *nfmalloc(size_t size) {
+  unsigned short *r, *r2, x;
+  r= nfmalloc_r(size); r2=r; x= (unsigned short)size;
+  while (size >= 2) { *r2++= x; size -= 2; }
+  return r;
+}
+#endif
+
+char *nfstrsave(const char *string) {
+  char *r;
+  
+  r= nfmalloc(strlen(string)+1);
+  strcpy(r,string);
+  return r;
+}
diff --git a/lib/parse.c b/lib/parse.c
new file mode 100644 (file)
index 0000000..15be97b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * parse.c - database file parsing, main package/field loop
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "parsedump.h"
+
+const struct fieldinfo fieldinfos[]= {
+  /* NB: capitalisation of these strings is important. */
+  { "Package",          f_name,           w_name                                   },
+  { "Essential",        f_boolean,        w_booleandefno,  PKGIFPOFF(essential)    },
+  { "Status",           f_status,         w_status                                 },
+  { "Priority",         f_priority,       w_priority                               },
+  { "Section",          f_section,        w_section                                },
+  { "Maintainer",       f_charfield,      w_charfield,     PKGIFPOFF(maintainer)   },
+  { "Architecture",     f_charfield,      w_charfield,     PKGIFPOFF(architecture) },
+  { "Source",           f_charfield,      w_charfield,     PKGIFPOFF(source)       },
+  { "Version",          f_charfield,      w_version,       PKGIFPOFF(version)      },
+  { "Revision",         f_charfield,      w_null,          PKGIFPOFF(revision)     },
+  { "Config-Version",   f_configversion,  w_configversion                          },
+  { "Replaces",         f_dependency,     w_dependency,    dep_replaces            },
+  { "Provides",         f_dependency,     w_dependency,    dep_provides            },
+  { "Depends",          f_dependency,     w_dependency,    dep_depends             },
+  { "Pre-Depends",      f_dependency,     w_dependency,    dep_predepends          },
+  { "Recommends",       f_dependency,     w_dependency,    dep_recommends          },
+  { "Suggests",         f_dependency,     w_dependency,    dep_suggests            },
+  { "Conflicts",        f_dependency,     w_dependency,    dep_conflicts           },
+  { "Conffiles",        f_conffiles,      w_conffiles                              },
+  { "Filename",         f_filecharf,      w_filecharf,     FILEFOFF(name)          },
+  { "Size",             f_filecharf,      w_filecharf,     FILEFOFF(size)          },
+  { "MD5sum",           f_filecharf,      w_filecharf,     FILEFOFF(md5sum)        },
+  { "MSDOS-Filename",   f_filecharf,      w_filecharf,     FILEFOFF(msdosname)     },
+  { "Description",      f_charfield,      w_charfield,     PKGIFPOFF(description)  },
+  /* Note that aliases are added to the nicknames table in parsehelp.c. */
+  {  0   /* sentinel - tells code that list is ended */                            }
+};
+#define NFIELDS (sizeof(fieldinfos)/sizeof(struct fieldinfo))
+const int nfields= NFIELDS;
+
+static void cu_parsedb(int argc, void **argv) { fclose((FILE*)*argv); }
+
+int parsedb(const char *filename, enum parsedbflags flags,
+            struct pkginfo **donep, FILE *warnto, int *warncount) {
+  /* warnto, warncount and donep may be null.
+   * If donep is not null only one package's information is expected.
+   */
+  static char readbuf[16384];
+  
+  FILE *file;
+  struct pkginfo newpig, *pigp;
+  struct pkginfoperfile *newpifp, *pifp;
+  struct arbitraryfield *arp, **larpp;
+  struct varbuf field, value;
+  int lno;
+  int pdone;
+  int fieldencountered[NFIELDS];
+  const struct fieldinfo *fip;
+  const struct nickname *nick;
+  const char *fieldname;
+  char *hyphen;
+  int *ip, i, c;
+
+  if (warncount) *warncount= 0;
+  newpifp= (flags & pdb_recordavailable) ? &newpig.available : &newpig.installed;
+  file= fopen(filename,"r");
+  if (!file) ohshite("failed to open package info file `%.255s' for reading",filename);
+
+  if (!donep) /* Reading many packages, use a nice big buffer. */
+    if (setvbuf(file,readbuf,_IOFBF,sizeof(readbuf)))
+      ohshite("unable to set buffering on status file");
+
+  push_cleanup(cu_parsedb,~0, 0,0, 1,(void*)file);
+  varbufinit(&field); varbufinit(&value);
+
+  lno= 1;
+  pdone= 0;
+  for (;;) { /* loop per package */
+    i= sizeof(fieldencountered)/sizeof(int); ip= fieldencountered;
+    while (i--) *ip++= 0;
+    blankpackage(&newpig);
+    blankpackageperfile(newpifp);
+    for (;;) {
+      c= getc(file); if (c!='\n' && c!=MSDOS_EOF_CHAR) break;
+      lno++;
+    }
+    if (c == EOF) break;
+    for (;;) { /* loop per field */
+      varbufreset(&field);
+      while (c!=EOF && !isspace(c) && c!=':' && c!=MSDOS_EOF_CHAR) {
+        varbufaddc(&field,c);
+        c= getc(file);
+      }
+      varbufaddc(&field,0);
+      while (c != EOF && c != '\n' && isspace(c)) c= getc(file);
+      if (c == EOF)
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "EOF after field name `%.50s'",field.buf);
+      if (c == '\n')
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "newline in field name `%.50s'",field.buf);
+      if (c == MSDOS_EOF_CHAR)
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "MSDOS EOF (^Z) in field name `%.50s'", field.buf);
+      if (c != ':')
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "field name `%.50s' must be followed by colon", field.buf);
+      varbufreset(&value);
+      for (;;) {
+        c= getc(file);
+        if (c == EOF || c == '\n' || !isspace(c)) break;
+      }
+      if (c == EOF)
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "EOF before value of field `%.50s' (missing final newline)",
+                 field.buf);
+      if (c == MSDOS_EOF_CHAR)
+        parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                 "MSDOS EOF char in value of field `%.50s' (missing newline?)",
+                 field.buf);
+      for (;;) {
+        if (c == '\n' || c == MSDOS_EOF_CHAR) {
+          lno++;
+          c= getc(file);
+          if (c == EOF || c == '\n' || !isspace(c)) break;
+          ungetc(c,file);
+          c= '\n';
+        } else if (c == EOF) {
+          parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                   "EOF during value of field `%.50s' (missing final newline)",
+                   field.buf);
+        }
+        varbufaddc(&value,c);
+        c= getc(file);
+      }
+      while (value.used && isspace(value.buf[value.used-1])) value.used--;
+      varbufaddc(&value,0);
+      fieldname= field.buf;
+      for (nick= nicknames; nick->nick && strcasecmp(nick->nick,fieldname); nick++);
+      if (nick->nick) fieldname= nick->canon;
+      for (fip= fieldinfos, ip= fieldencountered;
+           fip->name && strcasecmp(fieldname,fip->name);
+           fip++, ip++);
+      if (fip->name) {
+        if (*ip++)
+          parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                   "duplicate value for `%s' field", fip->name);
+        fip->rcall(&newpig,newpifp,flags,filename,lno-1,warnto,warncount,value.buf,fip);
+      } else {
+        if (strlen(fieldname)<2)
+          parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                   "user-defined field name `%s' too short", fieldname);
+        larpp= &newpifp->arbs;
+        while ((arp= *larpp) != 0) {
+          if (!strcasecmp(arp->name,fieldname))
+            parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                     "duplicate value for user-defined field `%.50s'", fieldname);
+          larpp= &arp->next;
+        }
+        arp= nfmalloc(sizeof(struct arbitraryfield));
+        arp->name= nfstrsave(fieldname);
+        arp->value= nfstrsave(value.buf);
+        arp->next= 0;
+        *larpp= arp;
+      }
+      if (c == EOF || c == '\n' || c == MSDOS_EOF_CHAR) break;
+    } /* loop per field */
+    if (pdone && donep)
+      parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+               "several package info entries found, only one allowed");
+    parsemustfield(file,filename,lno, warnto,warncount,&newpig,0,
+                   &newpig.name, "package name");
+    if ((flags & pdb_recordavailable) || newpig.status != stat_notinstalled) {
+      parsemustfield(file,filename,lno, warnto,warncount,&newpig,1,
+                     &newpifp->description, "description");
+      parsemustfield(file,filename,lno, warnto,warncount,&newpig,1,
+                     &newpifp->maintainer, "maintainer");
+      parsemustfield(file,filename,lno, warnto,warncount,&newpig,1,
+                     &newpifp->version, "version");
+    }
+    if (flags & pdb_recordavailable)
+      parsemustfield(file,filename,lno, warnto,warncount,&newpig,1,
+                     &newpifp->architecture, "architecture");
+    else if (newpifp->architecture && *newpifp->architecture)
+      newpifp->architecture= 0;
+
+    /* Break out the revision */
+    if (newpifp->revision) {
+      parseerr(file,filename,lno, warnto,warncount,&newpig,1,
+              "obsolete `Revision' or `Package-Revision' field used");
+    } else if (newpifp->version) {
+      hyphen= strrchr(newpifp->version,'-');
+      if (hyphen) {
+        *hyphen++= 0;
+        newpifp->revision= hyphen;
+      } else {
+        newpifp->revision= nfstrsave("");
+      }
+    }
+
+    /* Check the Config-Version information:
+     * If there is a Config-Version it is definitely to be used, but
+     * there shouldn't be one if the package is `installed' (in which case
+     * the Version and/or Revision will be copied) or if the package is
+     * `not-installed' (in which case there is no Config-Version).
+     */
+    if (!(flags & pdb_recordavailable)) {
+      if (newpig.configversion) {
+        if (newpig.status == stat_installed || newpig.status == stat_notinstalled)
+          parseerr(file,filename,lno, warnto,warncount,&newpig,0,
+                   "Configured-Version for package with inappropriate Status");
+      } else {
+        if (newpig.status == stat_installed) {
+          newpig.configversion= newpifp->version;
+          newpig.configrevision= newpifp->revision;
+        }
+      }
+    }
+
+    pigp= findpackage(newpig.name);
+    pifp= (flags & pdb_recordavailable) ? &pigp->available : &pigp->installed;
+    if (!pifp->valid) blankpackageperfile(pifp);
+
+    if (!(flags & pdb_preferversion) ||
+        versioncompare(newpifp->version,newpifp->revision,
+                       pifp->version,pifp->revision) >= 0) {
+      /* If we're ignoring older versions compare version numbers
+       * and only process this entry if it's a higher version.
+       */
+
+      /* Copy the priority and section across, but don't overwrite existing
+       * values if the pdb_weakclassification flag is set.
+       */
+      if (newpig.section && *newpig.section &&
+          !((flags & pdb_weakclassification) && pigp->section && *pigp->section))
+        pigp->section= newpig.section;
+      if (newpig.priority != pri_unknown &&
+          !((flags & pdb_weakclassification) && pigp->priority != pri_unknown)) {
+        pigp->priority= newpig.priority;
+        if (newpig.priority == pri_other) pigp->otherpriority= newpig.otherpriority;
+      }
+
+      /* Sort out the dependency mess. */
+      copy_dependency_links(pigp,&pifp->depends,newpifp->depends,
+                            (flags & pdb_recordavailable) ? 1 : 0);
+      /* Leave the `depended' pointer alone, we've just gone to such
+       * trouble to get it right :-).  The `depends' pointer in
+       * pifp was indeed also updated by copy_dependency_links,
+       * but since the value was that from newpifp anyway there's
+       * no need to copy it back.
+       */
+      newpifp->depended= pifp->depended;
+
+      /* Copy across data */
+      memcpy(pifp,newpifp,sizeof(struct pkginfoperfile));
+      if (!(flags & pdb_recordavailable)) {
+        pigp->want= newpig.want;
+        pigp->eflag= newpig.eflag;
+        pigp->status= newpig.status;
+        pigp->configversion= newpig.configversion;
+        pigp->configrevision= newpig.configrevision;
+        pigp->files= 0;
+      } else {
+        pigp->files= newpig.files;
+      }
+    }
+    if (donep) *donep= pigp;
+    pdone++;
+    if (c == EOF) break;
+    if (c == '\n') lno++;
+  }
+  if (ferror(file)) ohshite("failed to read from `%.255s'",filename);
+  pop_cleanup(0);
+  if (fclose(file)) ohshite("failed to close after read: `%.255s'",filename);
+  if (donep && !pdone) ohshit("no package information in `%.255s'",filename);
+
+  varbuffree(&field); varbuffree(&value);
+  return pdone;
+}
+
+void copy_dependency_links(struct pkginfo *pkg,
+                           struct dependency **updateme,
+                           struct dependency *newdepends,
+                           int available) {
+  /* This routine is used to update the `reverse' dependency pointers
+   * when new `forwards' information has been constructed.  It first
+   * removes all the links based on the old information.  The old
+   * information starts in *updateme; after much brou-ha-ha
+   * the reverse structures are created and *updateme is set
+   * to the value from newdepends.
+   *
+   * Parameters are:
+   * pkg - the package we're doing this for.  This is used to
+   *       construct correct uplinks.
+   * updateme - the forwards dependency pointer that we are to
+   *            update.  This starts out containing the old forwards
+   *            info, which we use to unthread the old reverse
+   *            links.  After we're done it is updated.
+   * newdepends - the value that we ultimately want to have in
+   *              updateme.
+   * It is likely that the backward pointer for the package in
+   * question (`depended') will be updated by this routine,
+   * but this will happen by the routine traversing the dependency
+   * data structures.  It doesn't need to be told where to update
+   * that; I just mention it as something that one should be
+   * cautious about.
+   */
+  struct dependency *dyp;
+  struct deppossi *dop;
+  struct pkginfoperfile *addtopifp;
+  
+  /* Delete `backward' (`depended') links from other packages to
+   * dependencies listed in old version of this one.  We do this by
+   * going through all the dependencies in the old version of this
+   * one and following them down to find which deppossi nodes to
+   * remove.
+   */
+  for (dyp= *updateme; dyp; dyp= dyp->next) {
+    for (dop= dyp->list; dop; dop= dop->next) {
+      if (dop->backrev)
+        dop->backrev->nextrev= dop->nextrev;
+      else
+        if (available)
+          dop->ed->available.depended= dop->nextrev;
+        else
+          dop->ed->installed.depended= dop->nextrev;
+      if (dop->nextrev)
+        dop->nextrev->backrev= dop->backrev;
+    }
+  }
+  /* Now fill in new `ed' links from other packages to dependencies listed
+   * in new version of this one, and set our uplinks correctly.
+   */
+  for (dyp= newdepends; dyp; dyp= dyp->next) {
+    dyp->up= pkg;
+    for (dop= dyp->list; dop; dop= dop->next) {
+      addtopifp= available ? &dop->ed->available : &dop->ed->installed;
+      if (!addtopifp->valid) blankpackageperfile(addtopifp);
+      dop->nextrev= addtopifp->depended;
+      dop->backrev= 0;
+      if (addtopifp->depended)
+        addtopifp->depended->backrev= dop;
+      addtopifp->depended= dop;
+    }
+  }
+  /* Finally, we fill in the new value. */
+  *updateme= newdepends;
+}
diff --git a/lib/parsedump.h b/lib/parsedump.h
new file mode 100644 (file)
index 0000000..ced6ec7
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * parse.c - declarations for in-core database reading/writing
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_PARSEDUMP_H
+#define DPKG_PARSEDUMP_H
+
+struct fieldinfo;
+
+struct nickname {
+  const char *nick;
+  const char *canon;
+};
+
+extern const struct fieldinfo fieldinfos[];
+extern const struct nickname nicknames[];
+extern const int nfields; /* = elements in fieldinfos, including the sentinels */
+
+#define PKGIFPOFF(f) ((char*)(&(((struct pkginfoperfile *)0x1000)->f)) - \
+                      (char*)(struct pkginfoperfile *)0x1000)
+#define PKGPFIELD(pifp,of,type) (*(type*)((char*)(pifp)+(of)))
+
+#define FILEFOFF(f) ((char*)(&(((struct filedetails *)0x1000)->f)) - \
+                     (char*)(struct filedetails *)0x1000)
+#define FILEFFIELD(filedetail,of,type) (*(type*)((char*)(filedetail)+(of)))
+
+typedef void freadfunction(struct pkginfo *pigp, struct pkginfoperfile *pifp,
+                           enum parsedbflags flags,
+                           const char *filename, int lno, FILE *warnto, int *warncount,
+                           const char *value, const struct fieldinfo *fip);
+freadfunction f_name, f_charfield, f_priority, f_section, f_status, f_filecharf;
+freadfunction f_boolean, f_dependency, f_conffiles, f_configversion;
+
+typedef void fwritefunction(struct varbuf*, const struct pkginfo*,
+                            const struct pkginfoperfile*, const struct fieldinfo*);
+fwritefunction w_name, w_charfield, w_priority, w_section, w_status, w_configversion;
+fwritefunction w_version, w_null, w_booleandefno, w_dependency, w_conffiles, w_filecharf;
+
+struct fieldinfo {
+  const char *name;
+  freadfunction *rcall;
+  fwritefunction *wcall;
+  int integer;
+};
+
+void parseerr(FILE *file, const char *filename, int lno, FILE *warnto, int *warncount,
+              const struct pkginfo *pigp, int warnonly,
+              const char *fmt, ...) PRINTFFORMAT(8,9);
+void parsemustfield(FILE *file, const char *filename, int lno,
+                    FILE *warnto, int *warncount,
+                    const struct pkginfo *pigp, int warnonly,
+                    char **value, const char *what);
+
+#define MSDOS_EOF_CHAR '\032' /* ^Z */
+
+#endif /* DPKG_PARSEDUMP_H */
diff --git a/lib/parsehelp.c b/lib/parsehelp.c
new file mode 100644 (file)
index 0000000..8d9c859
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * parsehelp.c - helpful routines for parsing and writing
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "parsedump.h"
+
+void parseerr(FILE *file, const char *filename, int lno, FILE *warnto, int *warncount,
+              const struct pkginfo *pigp, int warnonly,
+              const char *fmt, ...) {
+  va_list al;
+  char buf1[768], buf2[1000], *p, *q;
+  if (file && ferror(file)) ohshite("failed to read `%s' at line %d",filename,lno);
+  sprintf(buf1, "%s, in file `%.255s' near line %d",
+          warnonly ? "warning" : "parse error", filename, lno);
+  if (pigp && pigp->name) {
+    sprintf(buf2, " package `%.255s'", pigp->name);
+    strcat(buf1,buf2);
+  }
+  for (p=buf1, q=buf2; *p; *q++= *p++) if (*p == '%') *q++= '%';
+  strcpy(q,":\n "); strcat(q,fmt);
+  va_start(al,fmt);
+  if (!warnonly) ohshitv(buf2,al);
+  if (warncount) (*warncount)++;
+  if (warnto) {
+    strcat(q,"\n");
+    if (vfprintf(warnto,buf2,al) == EOF)
+      ohshite("failed to write parsing warning");
+  }
+  va_end(al);
+}
+
+const struct namevalue booleaninfos[]= {  /* Note !  These must be in order ! */
+  { "no",                             0                  },
+  { "yes",                            1                  },
+  {  0                                                   }
+};
+
+const struct namevalue priorityinfos[]= {  /* Note !  These must be in order ! */
+  { "required",                       pri_required     },
+  { "important",                      pri_important    },
+  { "standard",                       pri_standard     },
+  { "recommended",                    pri_recommended  }, /* fixme: obsolete */
+  { "optional",                       pri_optional     },
+  { "extra",                          pri_extra        },
+  { "contrib",                        pri_contrib      }, /* fixme: keep? */
+  { "this is a bug - please report",  pri_other        },
+  { "unknown",                        pri_unknown      },
+  
+  { "base",                           pri_required     }, /* fixme: alias, remove */
+  {  0                                                 }
+};
+
+const struct namevalue statusinfos[]= {  /* Note !  These must be in order ! */
+  { "not-installed",   stat_notinstalled    },
+  { "unpacked",        stat_unpacked        },
+  { "half-configured", stat_halfconfigured  },
+  { "installed",       stat_installed       },
+  { "half-installed",  stat_halfinstalled   },
+  { "config-files",    stat_configfiles     },
+  /* These are additional entries for reading only, in any order ... */
+  { "postinst-failed", stat_halfconfigured  }, /* fixme: backwards compat., remove */
+  { "removal-failed",  stat_halfinstalled   }, /* fixme: backwards compat., remove */
+  {  0                                      }
+};
+
+const struct namevalue eflaginfos[]= {  /* Note !  These must be in order ! */
+  { "ok",             eflagv_ok         },
+  { "hold",           eflagv_hold       },
+  { "reinstreq",      eflagv_reinstreq  },
+  { "hold-reinstreq", eflagv_both       },
+  {  0                                  }
+};
+
+const struct namevalue wantinfos[]= {  /* Note !  These must be in order ! */
+  { "unknown",   want_unknown    },
+  { "install",   want_install    },
+  { "deinstall", want_deinstall  },
+  { "purge",     want_purge      },
+  {  0                           }
+};
+
+const char *illegal_packagename(const char *p, const char **ep) {
+  static const char alsoallowed[]= "-_+.@:=%";
+  static char buf[150];
+  int c;
+  
+  if (!*p) return "may not be empty string";
+  if (!isalnum(*p)) return "must start with an alphanumeric";
+  if (!*++p) return "must be at least two characters";
+  while ((c= *p++)!=0)
+    if (!isalnum(c) && !strchr(alsoallowed,c)) break;
+  if (!c) return 0;
+  if (isspace(c) && ep) {
+    while (isspace(*p)) p++;
+    *ep= p; return 0;
+  }
+  sprintf(buf,
+          "character `%c' not allowed - only letters, digits and %s allowed",
+          c, alsoallowed);
+  return buf;
+}
+
+const struct nickname nicknames[]= {
+  /* NB: capitalisation of these strings is important. */
+  { "Recommended",       "Recommends"  },
+  { "Optional",          "Suggests"    },
+  { "Class",             "Priority"    },
+  { "Package-Revision",  "Revision"    },
+  { "Package_Revision",  "Revision"    },
+  {  0                                 }
+};
+
+void parsemustfield(FILE *file, const char *filename, int lno,
+                    FILE *warnto, int *warncount,
+                    const struct pkginfo *pigp, int warnonly,
+                    char **value, const char *what) {
+  if (!*value) {
+    parseerr(file,filename,lno, warnto,warncount,pigp,warnonly, "missing %s",what);
+    *value= nfstrsave("");
+  } else if (!**value) {
+    parseerr(file,filename,lno, warnto,warncount,pigp,warnonly,
+             "empty value for %s",what);
+  }
+}
+
+const char *skip_slash_dotslash(const char *p) {
+  while (p[0] == '/' || (p[0] == '.' && p[1] == '/')) p++;
+  return p;
+}
diff --git a/lib/showcright.c b/lib/showcright.c
new file mode 100644 (file)
index 0000000..57de25f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * showcright.c - show copyright file routine
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "dpkg.h"
+
+void showcopyright(const struct cmdinfo *c, const char *v) {
+  int fd;
+  fd= open(COPYINGFILE,O_RDONLY);
+  if (fd < 0) ohshite("cannot open GPL file " COPYINGFILE);
+  m_dup2(fd,0);
+  execlp(CAT,CAT,"-",(char*)0);
+  ohshite("unable to exec cat for displaying GPL file");
+}
diff --git a/lib/star.c b/lib/star.c
new file mode 100644 (file)
index 0000000..e43ddf0
--- /dev/null
@@ -0,0 +1,158 @@
+#include "tarfn.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+static int
+Read(void * userData, char * buffer, int length)
+{
+       /*
+        * If the status of the read function is < 0, it will be returned to
+        * the caller of TarExtractor().
+        */
+       return read((int)userData, buffer, length);
+}
+
+static int
+IOError(TarInfo * i)
+{
+       int     error = errno;  /* fflush() could cause errno to change */
+       fflush(stdout);
+       fprintf(stderr, "%s: %s\n", i->Name, strerror(error));
+
+       /*
+        * The status returned by a coroutine of TarExtractor(), if it
+        * is non-zero, will be returned to the caller of TarExtractor().
+        */
+       return -2;
+}
+
+static int
+ExtractFile(TarInfo * i)
+{
+       /*
+        * If you don't want to extract the file, you must advance the tape
+        * by the file size rounded up to the next 512-byte boundary and
+        * return 0.
+        */
+
+       int     fd = open(i->Name, O_CREAT|O_TRUNC|O_WRONLY, i->Mode & ~S_IFMT);
+       char    buffer[512];
+       size_t  size = i->Size;
+       struct utimbuf t;
+               
+       if ( fd < 0 )
+               return IOError(i);
+
+       printf("File: %s\n", i->Name);
+
+       while ( size > 0 ) {
+               size_t  writeSize = size >= 512 ? 512 : size;
+
+               if ( Read(i->UserData, buffer, 512) != 512 )
+                       return -1;      /* Something wrong with archive */
+               if ( write(fd, buffer, writeSize) != writeSize )
+                       return IOError(i);      /* Write failure. */
+
+               size -= writeSize;
+       }
+       /* fchown() and fchmod() are cheaper than chown() and chmod(). */
+       fchown(fd, i->UserID, i->GroupID);
+       fchmod(fd, i->Mode & ~S_IFMT);
+       close(fd);
+       t.actime = time(0);
+       t.modtime = i->ModTime;
+       utime(i->Name, &t);
+       return 0;
+}
+
+static int
+SetModes(TarInfo * i)
+{
+       struct utimbuf t;
+       chown(i->Name, i->UserID, i->GroupID);
+       chmod(i->Name, i->Mode & ~S_IFMT);
+       t.actime = time(0);
+       t.modtime = i->ModTime;
+       utime(i->Name, &t);
+        return 0;
+}
+
+static int
+MakeDirectory(TarInfo * i)
+{
+       printf("Directory: %s\n", i->Name);
+       if ( mkdir(i->Name, i->Mode & ~S_IFMT) != 0 ) {
+               if ( errno == EEXIST ) {
+                       struct stat s;
+                       if ( stat(i->Name, &s) != 0 || !(s.st_mode & S_IFDIR) )
+                               return IOError(i);
+               }
+               else
+                       return IOError(i);
+       }
+       SetModes(i);
+        return 0;
+}
+
+static int
+MakeHardLink(TarInfo * i)
+{
+       printf("Hard Link: %s\n", i->Name);
+
+       if ( link(i->LinkName, i->Name) != 0 )
+               return IOError(i);
+       SetModes(i);
+        return 0;
+}
+
+static int
+MakeSymbolicLink(TarInfo * i)
+{
+       printf("Symbolic Link: %s\n", i->Name);
+
+       if ( symlink(i->LinkName, i->Name) != 0 )
+               return -2;
+       SetModes(i);
+        return 0;
+}
+
+static int
+MakeSpecialFile(TarInfo * i)
+{
+       printf("Special File: %s\n", i->Name);
+
+       if ( mknod(i->Name, i->Mode, i->Device) != 0 )
+               return -2;
+       SetModes(i);
+        return 0;
+}
+
+static const TarFunctions      functions = {
+       Read,
+       ExtractFile,
+       MakeDirectory,
+       MakeHardLink,
+       MakeSymbolicLink,
+       MakeSpecialFile
+};
+
+int
+main(int argc, char * * argv)
+{
+       int     status = TarExtractor((void *)0, &functions);
+
+       if ( status == -1 ) {
+               fflush(stdout);
+               fprintf(stderr, "Error in archive format.\n");
+               return -1;
+       }
+       else
+               return status;
+}
diff --git a/lib/tarfn.c b/lib/tarfn.c
new file mode 100644 (file)
index 0000000..5a16a16
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Functions for extracting tar archives.
+ * Bruce Perens, April-May 1995
+ * Copyright (C) 1995 Bruce Perens
+ * This is free software under the GNU General Public License.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include "tarfn.h"
+
+struct TarHeader {
+       char Name[100];
+       char Mode[8];
+       char UserID[8];
+       char GroupID[8];
+       char Size[12];
+       char ModificationTime[12];
+       char Checksum[8];
+       char LinkFlag;
+       char LinkName[100];
+       char MagicNumber[8];
+       char UserName[32];
+       char GroupName[32];
+       char MajorDevice[8];
+       char MinorDevice[8];
+};
+typedef struct TarHeader       TarHeader;
+
+static const unsigned int      TarChecksumOffset
+       = (unsigned int)&(((TarHeader *)0)->Checksum);
+
+/* Octal-ASCII-to-long */
+static long
+OtoL(const char * s, int size)
+{
+       int     n = 0;
+
+       while ( *s == ' ' ) {
+               s++;
+               size--;
+       }
+
+       while ( --size >= 0 && *s >= '0' && *s <= '7' )
+               n = (n * 010) + (*s++ - '0');
+
+       return n;
+}
+
+static int
+DecodeTarHeader(char * block, TarInfo * d)
+{
+       TarHeader *                     h = (TarHeader *)block;
+       unsigned char *         s = (unsigned char *)block;
+       struct passwd *         passwd = 0;
+       struct group *          group = 0;
+       unsigned int            i;
+       long                            sum;
+       long                            checksum;
+
+       if ( *h->UserName )
+               passwd = getpwnam(h->UserName);
+       if ( *h->GroupName )
+               group = getgrnam(h->GroupName);
+
+       d->Name = h->Name;
+       d->LinkName = h->LinkName;
+       d->Mode = (mode_t)OtoL(h->Mode, sizeof(h->Mode));
+       d->Size = (size_t)OtoL(h->Size, sizeof(h->Size));
+       d->ModTime = (time_t)OtoL(h->ModificationTime
+        ,sizeof(h->ModificationTime));
+       d->Device = ((OtoL(h->MajorDevice, sizeof(h->MajorDevice)) & 0xff) << 8)
+        | (OtoL(h->MinorDevice, sizeof(h->MinorDevice)) & 0xff);
+       checksum = OtoL(h->Checksum, sizeof(h->Checksum));
+       d->UserID = (uid_t)OtoL(h->UserID, sizeof(h->UserID));
+       d->GroupID = (gid_t)OtoL(h->GroupID, sizeof(h->GroupID));
+       d->Type = (TarFileType)h->LinkFlag;
+
+       if ( passwd )
+               d->UserID = passwd->pw_uid;
+
+       if ( group )
+               d->GroupID = group->gr_gid;
+
+       
+       sum = ' ' * sizeof(h->Checksum);/* Treat checksum field as all blank */
+       for ( i = TarChecksumOffset; i > 0; i-- )
+               sum += *s++;
+       s += sizeof(h->Checksum);       /* Skip the real checksum field */
+       for ( i = (512 - TarChecksumOffset - sizeof(h->Checksum)); i > 0; i-- )
+               sum += *s++;
+
+       return ( sum == checksum );
+}
+
+extern int
+TarExtractor(
+ void *                        userData
+,const TarFunctions *  functions)
+{
+       int     status;
+       char    buffer[512];
+       TarInfo h;
+
+       h.UserData = userData;
+
+       while ( (status = functions->Read(userData, buffer, 512)) == 512 ) {
+               int     nameLength;
+
+               if ( !DecodeTarHeader(buffer, &h) ) {
+                       if ( h.Name[0] == '\0' ) {
+                               return 0;       /* End of tape */
+                       } else {
+                               errno = 0;      /* Indicates broken tarfile */
+                               return -1;      /* Header checksum error */
+                       }
+               }
+               if ( h.Name[0] == '\0' ) {
+                       errno = 0;      /* Indicates broken tarfile */
+                       return -1;      /* Bad header data */
+               }
+
+               nameLength = strlen(h.Name);
+
+               switch ( h.Type ) {
+               case NormalFile0:
+               case NormalFile1:
+                       /* Compatibility with pre-ANSI ustar */
+                       if ( h.Name[nameLength - 1] != '/' ) {
+                               status = (*functions->ExtractFile)(&h);
+                               break;
+                       }
+                       /* Else, Fall Through */
+               case Directory:
+                       h.Name[nameLength - 1] = '\0';
+                       status = (*functions->MakeDirectory)(&h);
+                       break;
+               case HardLink:
+                       status = (*functions->MakeHardLink)(&h);
+                       break;
+               case SymbolicLink:
+                       status = (*functions->MakeSymbolicLink)(&h);
+                       break;
+               case CharacterDevice:
+               case BlockDevice:
+               case FIFO:
+                       status = (*functions->MakeSpecialFile)(&h);
+                       break;
+               default:
+                       errno = 0;      /* Indicates broken tarfile */
+                       return -1;      /* Bad header field */
+               }
+               if ( status != 0 )
+                       return status;  /* Pass on status from coroutine */
+       }
+       if ( status > 0 ) {     /* Read partial header record */
+               errno = 0;      /* Indicates broken tarfile */
+               return -1;
+       } else {
+               return status;  /* Whatever I/O function returned */
+       }
+}
diff --git a/lib/varbuf.c b/lib/varbuf.c
new file mode 100644 (file)
index 0000000..2f12db7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * varbuf.c - variable length expandable buffer handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+void varbufaddc(struct varbuf *v, int c) {
+  if (v->used >= v->size) varbufextend(v);
+  v->buf[v->used++]= c;
+}
+
+void varbufaddstr(struct varbuf *v, const char *s) {
+  int l, ou;
+  l= strlen(s);
+  ou= v->used;
+  v->used += l;
+  if (v->used >= v->size) varbufextend(v);
+  memcpy(v->buf + ou, s, l);
+}
+
+void varbufinit(struct varbuf *v) {
+  /* NB: dbmodify.c does its own init to get a big buffer */
+  v->size= v->used= 0;
+  v->buf= 0;
+}
+
+void varbufreset(struct varbuf *v) {
+  v->used= 0;
+}
+
+void varbufextend(struct varbuf *v) {
+  int newsize;
+  char *newbuf;
+
+  newsize= v->size + 80 + v->used;
+  newbuf= realloc(v->buf,newsize);
+  if (!newbuf) ohshite("failed to realloc for variable buffer");
+  v->size= newsize;
+  v->buf= newbuf;
+}
+
+void varbuffree(struct varbuf *v) {
+  free(v->buf); v->buf=0; v->size=0; v->used=0;
+}
diff --git a/lib/vercmp.c b/lib/vercmp.c
new file mode 100644 (file)
index 0000000..a2fac63
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * vercmp.c - comparison of version numbers
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "parsedump.h"
+
+static int verrevcmp(const char *val, const char *ref) {
+  int vc, rc;
+  long vl, rl;
+  const char *vp, *rp;
+
+  if (!val) val= "";
+  if (!ref) ref= "";
+  for (;;) {
+    vp= val;  while (*vp && !isdigit(*vp)) vp++;
+    rp= ref;  while (*rp && !isdigit(*rp)) rp++;
+    for (;;) {
+      vc= val == vp ? 0 : *val++;
+      rc= ref == rp ? 0 : *ref++;
+      if (!rc && !vc) break;
+      if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */
+      if (rc && !isalpha(rc)) rc += 256;
+      if (vc != rc) return vc - rc;
+    }
+    val= vp;
+    ref= rp;
+    vl=0;  if (isdigit(*vp)) vl= strtol(val,(char**)&val,10);
+    rl=0;  if (isdigit(*rp)) rl= strtol(ref,(char**)&ref,10);
+    if (vl != rl) return vl - rl;
+    if (!*val && !*ref) return 0;
+    if (!*val) return -1;
+    if (!*ref) return +1;
+  }
+}
+
+int versioncompare(const char *version, const char *revision,
+                   const char *refversion, const char *refrevision) {
+  int r;
+  r= verrevcmp(version,refversion);  if (r) return r;
+  return verrevcmp(revision,refrevision);
+}
diff --git a/main/Makefile.in b/main/Makefile.in
new file mode 100644 (file)
index 0000000..9bb9a38
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+
+SRC = main.c enquiry.c filesdb.c archives.c processarc.c cleanup.c \
+      packages.c configure.c remove.c help.c depcon.c errors.c update.c
+
+OBJ = main.o enquiry.o filesdb.o archives.o processarc.o cleanup.o \
+      packages.o configure.o remove.o help.o depcon.o errors.o update.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+OPTCFLAGS = @OPTCFLAGS@
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib -ldpkg $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+ALL_CFLAGS_OPT = $(ALL_CFLAGS) $(OPTCFLAGS)
+
+.SUFFIXES:     .c .o
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+all:           dpkg
+
+dpkg:          $(OBJ) ../lib/libdpkg.a
+               $(CC) $(LDFLAGS) -o dpkg $(OBJ) $(LIBS)
+
+# This next file is very heavily used, and should be optimised
+# for speed rather than space.  (ALL_CFLAGS_OPT usually means -O3.)
+filesdb.o:     filesdb.c
+               $(CC) $(ALL_CFLAGS_OPT) -c $<
+
+archtable.inc: ../archtable
+               perl -ne 'print "  { \"$$1\",$$2\"$$3\" },\n" \
+                          if m/^\s*(\w+)(\s+)(\w+)\s*$$/' \
+                       ../archtable >archtable.inc.new
+               mv archtable.inc.new archtable.inc
+
+clean:
+               rm -f *.o core dpkg *.new
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+               rm -rf t updates status available *.old
+
+install:       all
+               $(INSTALL_PROGRAM) -s dpkg $(bindir)/dpkg
+               $(INSTALL_DATA) dpkg.8 $(man8dir)/dpkg.$(man8)
+
+$(OBJ):                        main.h ../config.h ../include/dpkg.h ../include/dpkg-db.h
+main.o:                                                ../version.h
+main.o enquiry.o errors.o update.o:            ../include/myopt.h
+enquiry.o:                                     filesdb.h archtable.inc
+filesdb.o:                                     filesdb.h
+packages.o remove.o configure.o:               filesdb.h ../include/myopt.h
+archives.o processarc.o help.o:                        filesdb.h ../include/myopt.h
+archives.o processarc.o:                       archives.h ../include/tarfn.h
diff --git a/main/archives.c b/main/archives.c
new file mode 100644 (file)
index 0000000..bfe8de4
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * dpkg - main program for package management
+ * archives.c - actions that process archive files, mainly unpack
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <assert.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+#include "tarfn.h"
+
+#include "filesdb.h"
+#include "main.h"
+#include "archives.h"
+
+void cu_pathname(int argc, void **argv) {
+  ensure_pathname_nonexisting((char*)(argv[0]));
+} 
+
+void cu_backendpipe(int argc, void **argv) {
+  FILE *f= *(FILE**)argv[0];
+  if (f) fclose(f);
+} 
+
+int tarfileread(void *ud, char *buf, int len) {
+  struct tarcontext *tc= (struct tarcontext*)ud;
+  int r;
+  r= fread(buf,1,len,tc->backendpipe);
+  if (r != len && ferror(tc->backendpipe))
+    ohshite("error reading from " BACKEND " pipe");
+  return r;
+}
+
+int fnameidlu;
+struct varbuf fnamevb;
+struct varbuf fnametmpvb;
+struct varbuf fnamenewvb;
+struct packageinlist *deconfigure= 0;
+
+static time_t currenttime;
+
+static int does_replace(struct pkginfo *newpigp,
+                          struct pkginfoperfile *newpifp,
+                          struct pkginfo *oldpigp) {
+  struct dependency *dep;
+  
+  debug(dbg_depcon,"does_replace new=%s old=%s (%s)",newpigp->name,
+        oldpigp->name,versiondescribe(oldpigp->installed.version,
+                                      oldpigp->installed.revision));
+  for (dep= newpifp->depends; dep; dep= dep->next) {
+    if (dep->type != dep_replaces || dep->list->ed != oldpigp) continue;
+    debug(dbg_depcondetail,"does_replace ... found old, version %s",
+          versiondescribe(dep->list->version,dep->list->revision));
+    if (!versionsatisfied(&oldpigp->installed,dep->list)) continue;
+    debug(dbg_depcon,"does_replace ... yes");
+    return 1;
+  }
+  debug(dbg_depcon,"does_replace ... no");
+  return 0;
+}
+
+static void newtarobject_utime(const char *path, struct TarInfo *ti) {
+  struct utimbuf utb;
+  utb.actime= currenttime;
+  utb.modtime= ti->ModTime;
+  if (utime(path,&utb))
+    ohshite("error setting timestamps of `%.255s'",ti->Name);
+}
+
+static void newtarobject_allmodes(const char *path, struct TarInfo *ti) {
+  if (chown(path,ti->UserID,ti->GroupID))
+    ohshite("error setting ownership of `%.255s'",ti->Name);
+  if (chmod(path,ti->Mode & ~S_IFMT))
+    ohshite("error setting permissions of `%.255s'",ti->Name);
+  newtarobject_utime(path,ti);
+}
+
+void setupfnamevbs(const char *filename) {
+  fnamevb.used= fnameidlu;
+  varbufaddstr(&fnamevb,filename);
+  varbufaddc(&fnamevb,0);
+
+  fnametmpvb.used= fnameidlu;
+  varbufaddstr(&fnametmpvb,filename);
+  varbufaddstr(&fnametmpvb,DPKGTEMPEXT);
+  varbufaddc(&fnametmpvb,0);
+
+  fnamenewvb.used= fnameidlu;
+  varbufaddstr(&fnamenewvb,filename);
+  varbufaddstr(&fnamenewvb,DPKGNEWEXT);
+  varbufaddc(&fnamenewvb,0);
+
+  debug(dbg_eachfiledetail, "setupvnamevbs main=`%s' tmp=`%s' new=`%s'",
+        fnamevb.buf, fnametmpvb.buf, fnamenewvb.buf);
+}
+
+int unlinkorrmdir(const char *filename) {
+  /* Returns 0 on success or -1 on failure, just like unlink & rmdir */
+  int r, e;
+  
+  if (!rmdir(filename)) {
+    debug(dbg_eachfiledetail,"unlinkorrmdir `%s' rmdir OK",filename);
+    return 0;
+  }
+  
+  if (errno != ENOTDIR) {
+    e= errno;
+    debug(dbg_eachfiledetail,"unlinkorrmdir `%s' rmdir %s",filename,strerror(e));
+    errno= e; return -1;
+  }
+  
+  r= unlink(filename); e= errno;
+  debug(dbg_eachfiledetail,"unlinkorrmdir `%s' unlink %s",
+        filename, r ? strerror(e) : "OK");
+  errno= e; return r;
+}
+     
+int tarobject(struct TarInfo *ti) {
+  static struct varbuf conffderefn, hardlinkfn, symlinkfn;
+  const char *usename;
+    
+  struct tarcontext *tc= (struct tarcontext*)ti->UserData;
+  int statr, fd, r, i, existingdirectory;
+  struct stat stab, stabd;
+  size_t sz, wsz;
+  FILE *thefile;
+  char databuf[TARBLKSZ];
+  struct fileinlist *nifd;
+  struct pkginfo *divpkg, *otherpkg;
+  struct filepackages *packageslump;
+
+  /* Append to list of files.
+   * The trailing / put on the end of names in tarfiles has already
+   * been stripped by TarExtractor (lib/tarfn.c).
+   */
+  nifd= m_malloc(sizeof(struct fileinlist));
+  nifd->namenode= findnamenode(ti->Name);
+  nifd->next= 0; *tc->newfilesp= nifd; tc->newfilesp= &nifd->next;
+  nifd->namenode->flags |= fnnf_new_inarchive;
+
+  debug(dbg_eachfile,
+        "tarobject ti->Name=`%s' Mode=%lo owner=%u.%u Type=%d(%c)"
+        " ti->LinkName=`%s' namenode=`%s' flags=%o instead=`%s'",
+        ti->Name, (long)ti->Mode, (unsigned)ti->UserID, (unsigned)ti->GroupID, ti->Type,
+        ti->Type == '\0' ? '_' :
+        ti->Type >= '0' && ti->Type <= '6' ? "-hlcbdp"[ti->Type - '0'] : '?',
+        ti->LinkName,
+        nifd->namenode->name, nifd->namenode->flags,
+        nifd->namenode->divert && nifd->namenode->divert->useinstead
+        ? nifd->namenode->divert->useinstead->name : "<none>");
+
+  if (nifd->namenode->divert && nifd->namenode->divert->camefrom) {
+    divpkg= nifd->namenode->divert->pkg;
+    forcibleerr(fc_overwritediverted,
+                "trying to overwrite `%.250s', which is the "
+                "diverted version of `%.250s'%.10s%.100s%.10s",
+                nifd->namenode->name,
+                nifd->namenode->divert->camefrom->name,
+                divpkg ? " (package: " : "",
+                divpkg ? divpkg->name : "",
+                divpkg ? ")" : "");
+  }
+
+  usename= namenodetouse(nifd->namenode,tc->pkg)->name + 1; /* Skip the leading `/' */
+
+  if (nifd->namenode->flags & fnnf_new_conff) {
+    /* If it's a conffile we have to extract it next to the installed
+     * version (ie, we do the usual link-following).
+     */
+    if (conffderef(tc->pkg, &conffderefn, usename))
+      usename= conffderefn.buf;
+    debug(dbg_conff,"tarobject fnnf_new_conff deref=`%s'",usename);
+  }
+  
+  setupfnamevbs(usename);
+
+  statr= lstat(fnamevb.buf,&stab);
+  if (statr) {
+    /* The lstat failed. */
+    if (errno != ENOENT && errno != ENOTDIR)
+      ohshite("unable to stat `%.255s' (which I was about to install)",ti->Name);
+    /* OK, so it doesn't exist.
+     * However, it's possible that we were in the middle of some other
+     * backup/restore operation and were rudely interrupted.
+     * So, we see if we have .dpkg-tmp, and if so we restore it.
+     */
+    if (rename(fnametmpvb.buf,fnamevb.buf)) {
+      if (errno != ENOENT && errno != ENOTDIR)
+        ohshite("unable to clean up mess surrounding `%.255s' before "
+                "installing another version",ti->Name);
+      debug(dbg_eachfiledetail,"tarobject nonexistent");
+    } else {
+      debug(dbg_eachfiledetail,"tarobject restored tmp to main");
+      statr= lstat(fnamevb.buf,&stab);
+      if (statr) ohshite("unable to stat restored `%.255s' before installing"
+                         " another version", ti->Name);
+    }
+  } else {
+    debug(dbg_eachfiledetail,"tarobject already exists");
+  }
+
+  /* Check to see if it's a directory or link to one and we don't need to
+   * do anything.  This has to be done now so that we don't die due to
+   * a file overwriting conflict.
+   */
+  existingdirectory= 0;
+  switch (ti->Type) {
+  case SymbolicLink:
+    /* If it's already an existing directory, do nothing. */
+    if (!statr && S_ISDIR(stab.st_mode)) {
+      debug(dbg_eachfiledetail,"tarobject SymbolicLink exists as directory");
+      existingdirectory= 1;
+    }
+    break;
+  case Directory:
+    /* If it's already an existing directory, do nothing. */
+    if (!stat(fnamevb.buf,&stabd) && S_ISDIR(stabd.st_mode)) {
+      debug(dbg_eachfiledetail,"tarobject Directory exists");
+      existingdirectory= 1;
+    }
+    break;
+  case NormalFile0: case NormalFile1:
+  case CharacterDevice: case BlockDevice:
+  case HardLink:
+    break;
+  default:
+    ohshit("archive contained object `%.255s' of unknown type 0x%x",ti->Name,ti->Type);
+  }
+
+  if (!existingdirectory) {
+    for (packageslump= nifd->namenode->packages;
+         packageslump;
+         packageslump= packageslump->more) {
+      for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+        otherpkg= packageslump->pkgs[i];
+        if (otherpkg == tc->pkg) continue;
+        debug(dbg_eachfile, "tarobject ... found in %s",otherpkg->name);
+        if (nifd->namenode->divert && nifd->namenode->divert->useinstead) {
+          /* Right, so we may be diverting this file.  This makes the conflict
+           * OK iff one of us is the diverting package (we don't need to
+           * check for both being the diverting package, obviously).
+           */
+          divpkg= nifd->namenode->divert->pkg;
+          debug(dbg_eachfile, "tarobject ... diverted, divpkg=%s\n",divpkg->name);
+          if (otherpkg == divpkg || tc->pkg == divpkg) continue;
+        }
+        /* Nope ?  Hmm, file conflict, perhaps.  Check Replaces. */
+        if (otherpkg->clientdata->replacingfilesandsaid) continue;
+        /* Perhaps we're removing a conflicting package ? */
+        if (otherpkg->clientdata->istobe == itb_remove) continue;
+        if (does_replace(tc->pkg,&tc->pkg->available,otherpkg)) {
+          printf("Replacing files in old package %s ...\n",otherpkg->name);
+          otherpkg->clientdata->replacingfilesandsaid= 1;
+        } else {
+          forcibleerr(fc_overwrite,
+                      "trying to overwrite `%.250s', which is also in package %.250s",
+                      nifd->namenode->name,otherpkg->name);
+        }
+      }
+    }
+  }
+       
+  /* Now, at this stage we want to make sure neither of .dpkg-new and .dpkg-tmp
+   * are hanging around.
+   */
+  ensure_pathname_nonexisting(fnamenewvb.buf);
+  ensure_pathname_nonexisting(fnametmpvb.buf);
+
+  if (existingdirectory) return 0;
+
+  /* Now we start to do things that we need to be able to undo
+   * if something goes wrong.
+   */
+  push_cleanup(cu_installnew,~ehflag_normaltidy, 0,0, 1,(void*)nifd);
+
+  /* Extract whatever it is as .dpkg-new ... */
+  switch (ti->Type) {
+  case NormalFile0: case NormalFile1:
+    fd= open(fnamenewvb.buf, O_CREAT|O_EXCL|O_WRONLY,
+             ti->Mode & (S_IRUSR|S_IRGRP|S_IROTH));
+    if (fd < 0) ohshite("unable to create `%.255s'",ti->Name);
+    thefile= fdopen(fd,"w");
+    if (!thefile) { close(fd); ohshite("unable to fdopen for `%.255s'",ti->Name); }
+    push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)thefile);
+    debug(dbg_eachfiledetail,"tarobject NormalFile[01] open size=%lu",
+          (unsigned long)ti->Size);
+    for (sz= ti->Size; sz > 0; sz -= wsz) {
+      wsz= sz > TARBLKSZ ? TARBLKSZ : sz;
+      r= fread(databuf,1,TARBLKSZ,tc->backendpipe);
+      if (r<TARBLKSZ) {
+        if (ferror(tc->backendpipe)) {
+          ohshite("error reading " BACKEND " during `%.255s'",ti->Name);
+        } else {
+          errno= 0;
+          return -1;
+        }
+      }
+      if (fwrite(databuf,1,wsz,thefile) != wsz)
+        ohshite("error writing to `%.255s'",ti->Name);
+    }
+    if (fchown(fd,ti->UserID,ti->GroupID))
+      ohshite("error setting ownership of `%.255s'",ti->Name);
+    if (fchmod(fd,ti->Mode & ~S_IFMT))
+      ohshite("error setting permissions of `%.255s'",ti->Name);
+    pop_cleanup(ehflag_normaltidy); /* thefile= fdopen(fd) */
+    if (fclose(thefile))
+      ohshite("error closing/writing `%.255s'",ti->Name);
+    newtarobject_utime(fnamenewvb.buf,ti);
+    break;
+  case CharacterDevice: case BlockDevice:
+    if (mknod(fnamenewvb.buf,ti->Mode & S_IFMT,ti->Device))
+      ohshite("error creating device `%.255s'",ti->Name);
+    debug(dbg_eachfiledetail,"tarobject CharacterDevice|BlockDevice");
+    newtarobject_allmodes(fnamenewvb.buf,ti);
+    break;
+  case HardLink:
+    varbufreset(&hardlinkfn);
+    varbufaddstr(&hardlinkfn,instdir); varbufaddc(&hardlinkfn,'/');
+    varbufaddstr(&hardlinkfn,ti->LinkName); varbufaddc(&hardlinkfn,0);
+    if (link(hardlinkfn.buf,fnamenewvb.buf))
+      ohshite("error creating hard link `%.255s'",ti->Name);
+    debug(dbg_eachfiledetail,"tarobject HardLink");
+    newtarobject_allmodes(fnamenewvb.buf,ti);
+    break;
+  case SymbolicLink:
+    /* We've already cheched for an existing directory. */
+    if (symlink(ti->LinkName,fnamenewvb.buf))
+      ohshite("error creating symbolic link `%.255s'",ti->Name);
+    debug(dbg_eachfiledetail,"tarobject SymbolicLink creating");
+    if (chown(fnamenewvb.buf,ti->UserID,ti->GroupID))
+      ohshite("error setting ownership of symlink `%.255s'",ti->Name);
+    break;
+  case Directory:
+    /* We've already checked for an existing directory. */
+    if (mkdir(fnamenewvb.buf,
+              ti->Mode & (S_IRUSR|S_IRGRP|S_IROTH | S_IXUSR|S_IXGRP|S_IXOTH)))
+      ohshite("error creating directory `%.255s'",ti->Name);
+    debug(dbg_eachfiledetail,"tarobject Directory creating");
+    newtarobject_allmodes(fnamenewvb.buf,ti);
+    break;
+  default:
+    internerr("bad tar type, but already checked");
+  }
+  /*
+   * Now we have extracted the new object in .dpkg-new (or, if the
+   * file already exists as a directory and we were trying to extract
+   * a directory or symlink, we returned earlier, so we don't need
+   * to worry about that here).
+   */
+
+  /* First, check to see if it's a conffile.  If so we don't install
+   * it now - we leave it in .dpkg-new for --configure to take care of
+   */
+  if (nifd->namenode->flags & fnnf_new_conff) {
+    debug(dbg_conffdetail,"tarobject conffile extracted");
+    nifd->namenode->flags |= fnnf_elide_other_lists;
+    return 0;
+  }
+
+  /* Now we install it.  If we can do an atomic overwrite we do so.
+   * If not we move aside the old file and then install the new.
+   * The backup file will be deleted later.
+   */
+  if (statr) { /* Don't try to back it up if it didn't exist. */
+    debug(dbg_eachfiledetail,"tarobject new - no backup");
+  } else {
+    if (ti->Type == Directory || S_ISDIR(stab.st_mode)) {
+      /* One of the two is a directory - can't do atomic install. */
+      debug(dbg_eachfiledetail,"tarobject directory, nonatomic");
+      nifd->namenode->flags |= fnnf_no_atomic_overwrite;
+      if (rename(fnamevb.buf,fnametmpvb.buf))
+        ohshite("unable to move aside `%.255s' to install new version",ti->Name);
+    } else if (S_ISLNK(stab.st_mode)) {
+      /* We can't make a symlink with two hardlinks, so we'll have to copy it.
+       * (Pretend that making a copy of a symlink is the same as linking to it.)
+       */
+      varbufreset(&symlinkfn);
+      do {
+        varbufextend(&symlinkfn);
+        r= readlink(fnamevb.buf,symlinkfn.buf,symlinkfn.size);
+        if (r<0) ohshite("unable to read link `%.255s'",ti->Name);
+      } while (r == symlinkfn.size);
+      symlinkfn.used= r; varbufaddc(&symlinkfn,0);
+      if (symlink(symlinkfn.buf,fnametmpvb.buf))
+        ohshite("unable to make backup symlink for `%.255s'",ti->Name);
+      if (chown(fnametmpvb.buf,stab.st_uid,stab.st_gid))
+        ohshite("unable to chown backup symlink for `%.255s'",ti->Name);
+    } else {
+      debug(dbg_eachfiledetail,"tarobject nondirectory, `link' backup");
+      if (link(fnamevb.buf,fnametmpvb.buf))
+        ohshite("unable to make backup link of `%.255s' before installing new version",
+                ti->Name);
+    }
+  }
+
+  if (rename(fnamenewvb.buf,fnamevb.buf))
+    ohshite("unable to install new version of `%.255s'",ti->Name);
+
+  nifd->namenode->flags |= fnnf_elide_other_lists;
+
+  debug(dbg_eachfiledetail,"tarobject done and installed");
+  return 0;
+}
+
+static int try_remove_can(struct deppossi *pdep,
+                          struct pkginfo *fixbyrm,
+                          const char *why) {
+  struct packageinlist *newdeconf;
+  
+  if (force_depends(pdep)) {
+    fprintf(stderr, DPKG ": warning - "
+            "ignoring dependency problem with removal of %s:\n%s",
+            fixbyrm->name, why);
+    return 1;
+  } else if (f_autodeconf) {
+    if (pdep->up->up->installed.essential) {
+      if (fc_removeessential) {
+        fprintf(stderr, DPKG ": warning - considering deconfiguration of essential\n"
+                " package %s, to enable removal of %s.\n",
+                pdep->up->up->name,fixbyrm->name);
+      } else {
+        fprintf(stderr, DPKG ": no, %s is essential, will not deconfigure\n"
+                " it in order to enable removal of %s.\n",
+                pdep->up->up->name,fixbyrm->name);
+        return 0;
+      }
+    }
+    pdep->up->up->clientdata->istobe= itb_deconfigure;
+    newdeconf= m_malloc(sizeof(struct packageinlist));
+    newdeconf->next= deconfigure;
+    newdeconf->pkg= pdep->up->up;
+    deconfigure= newdeconf;
+    return 1;
+  } else {
+    fprintf(stderr, DPKG ": no, cannot remove %s (--auto-deconfigure will help):\n%s",
+            fixbyrm->name, why);
+    return 0;
+  }
+}
+
+void check_conflict(struct dependency *dep, struct pkginfo *pkg,
+                    const char *pfilename, struct pkginfo **conflictorp) {
+  struct pkginfo *fixbyrm;
+  struct deppossi *pdep, flagdeppossi;
+  struct varbuf conflictwhy, removalwhy;
+  struct dependency *providecheck;
+  
+  varbufinit(&conflictwhy);
+  varbufinit(&removalwhy);
+
+  fixbyrm= 0;
+  if (depisok(dep, &conflictwhy, *conflictorp ? 0 : &fixbyrm, 0)) {
+    varbuffree(&conflictwhy);
+    varbuffree(&removalwhy);
+    return;
+  }
+  if (fixbyrm &&
+      ((pkg->available.essential && fixbyrm->installed.essential) ||
+       ((fixbyrm->want != want_install || does_replace(pkg,&pkg->available,fixbyrm)) &&
+        (!fixbyrm->installed.essential || fc_removeessential)))) {
+    ensure_package_clientdata(fixbyrm);
+    assert(fixbyrm->clientdata->istobe == itb_normal);
+    fixbyrm->clientdata->istobe= itb_remove;
+    fprintf(stderr, DPKG ": considering removing %s in favour of %s ...\n",
+            fixbyrm->name, pkg->name);
+    if (fixbyrm->status != stat_installed) {
+      fprintf(stderr,
+              "%s is not properly installed - ignoring any dependencies on it.\n",
+              fixbyrm->name);
+      pdep= 0;
+    } else {
+      for (pdep= fixbyrm->installed.depended;
+           pdep;
+           pdep= pdep->nextrev) {
+        if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends) continue;
+        if (depisok(pdep->up, &removalwhy, 0,0)) continue;
+        varbufaddc(&removalwhy,0);
+        if (!try_remove_can(pdep,fixbyrm,removalwhy.buf))
+          break;
+      }
+      if (!pdep) {
+        /* If we haven't found a reason not to yet, let's look some more. */
+        for (providecheck= fixbyrm->installed.depends;
+             providecheck;
+             providecheck= providecheck->next) {
+          if (providecheck->type != dep_provides) continue;
+          for (pdep= providecheck->list->ed->installed.depended;
+               pdep;
+               pdep= pdep->nextrev) {
+            if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends)
+              continue;
+            if (depisok(pdep->up, &removalwhy, 0,0)) continue;
+            varbufaddc(&removalwhy,0);
+            fprintf(stderr, DPKG
+                    ": may have trouble removing %s, as it provides %s ...\n",
+                    fixbyrm->name, providecheck->list->ed->name);
+            if (!try_remove_can(pdep,fixbyrm,removalwhy.buf))
+              goto break_from_both_loops_at_once;
+          }
+        }
+      break_from_both_loops_at_once:;
+      }
+    }
+    if (!pdep && skip_due_to_hold(fixbyrm)) {
+      pdep= &flagdeppossi;
+    }
+    if (!pdep && (fixbyrm->eflag & eflagf_reinstreq)) {
+      if (fc_removereinstreq) {
+        fprintf(stderr, DPKG ": package %s requires reinstallation, but will"
+                " remove anyway as you request.\n", fixbyrm->name);
+      } else {
+        fprintf(stderr, DPKG ": package %s requires reinstallation, will not remove.\n",
+                fixbyrm->name);
+        pdep= &flagdeppossi;
+      }
+    }
+    if (!pdep) {
+      /* This conflict is OK - we'll remove the conflictor. */
+      *conflictorp= fixbyrm;
+      varbuffree(&conflictwhy); varbuffree(&removalwhy);
+      fprintf(stderr, DPKG ": yes, will remove %s in favour of %s.\n",
+              fixbyrm->name, pkg->name);
+      return;
+    }
+    fixbyrm->clientdata->istobe= itb_normal; /* put it back */
+  }
+  varbufaddc(&conflictwhy,0);
+  fprintf(stderr, DPKG ": regarding %s containing %s:\n%s",
+          pfilename, pkg->name, conflictwhy.buf);
+  if (!force_conflicts(dep->list))
+    ohshit("conflicting packages - not installing %.250s",pkg->name);
+  fprintf(stderr, DPKG ": warning - ignoring conflict, may proceed anyway !\n");
+  varbuffree(&conflictwhy);
+  
+  return;
+}
+
+void cu_cidir(int argc, void **argv) {
+  char *cidir= (char*)argv[0];
+  char *cidirrest= (char*)argv[1];
+  *cidirrest= 0;
+  ensure_pathname_nonexisting(cidir);
+}  
+
+void cu_fileslist(int argc, void **argv) {
+  struct fileinlist **headp= (struct fileinlist**)argv[0];
+  struct fileinlist *current, *next;
+  for (current= *headp; current; current= next) {
+    next= current->next;
+    free(current);
+  }
+}  
+
+void archivefiles(const char *const *argv) {
+  const char *volatile thisarg;
+  const char *const *volatile argp;
+  jmp_buf ejbuf;
+  int pi[2], fc, nfiles, c, i;
+  FILE *pf;
+  static struct varbuf findoutput;
+  const char **arglist;
+  char *p;
+
+  if (f_recursive) {
+    
+    if (!*argv)
+      badusage("--%s --recursive needs at least one path argument",cipaction->olong);
+    
+    m_pipe(pi);
+    if (!(fc= m_fork())) {
+      const char *const *ap;
+      int i;
+      m_dup2(pi[1],1); close(pi[0]);
+      for (i=0, ap=argv; *ap; ap++, i++);
+      arglist= m_malloc(sizeof(char*)*(i+15));
+      arglist[0]= FIND;
+      for (i=1, ap=argv; *ap; ap++, i++) {
+        if (strchr(FIND_EXPRSTARTCHARS,(*ap)[0])) {
+          char *a;
+          a= m_malloc(strlen(*ap)+10);
+          strcpy(a,"./");
+          strcat(a,*ap);
+          arglist[i]= a;
+        } else {
+          arglist[i]= *ap;
+        }
+      }
+      arglist[i++]= "-follow"; /*  When editing these, make sure that     */
+      arglist[i++]= "-name";   /*  arglist is mallocd big enough, above.  */
+      arglist[i++]= ARCHIVE_FILENAME_PATTERN;
+      arglist[i++]= "-type";
+      arglist[i++]= "f";
+      arglist[i++]= "-print0";
+      arglist[i++]= 0;
+      execvp(FIND, (char* const*)arglist);
+      ohshite("failed to exec " FIND " for --recursive");
+    }
+
+    nfiles= 0;
+    pf= fdopen(pi[0],"r");  if (!pf) ohshite("failed to fdopen find's pipe");
+    close(pi[1]);
+    varbufreset(&findoutput);
+    while ((c= fgetc(pf)) != EOF) {
+      varbufaddc(&findoutput,c);
+      if (!c) nfiles++;
+    }
+    if (ferror(pf)) ohshite("error reading find's pipe");
+    if (fclose(pf)) ohshite("error closing find's pipe");
+    waitsubproc(fc,"find",0);
+
+    if (!nfiles) ohshit("searched, but found no packages (files matching "
+                        ARCHIVE_FILENAME_PATTERN ")");
+
+    varbufaddc(&findoutput,0);
+    varbufaddc(&findoutput,0);
+    
+    arglist= m_malloc(sizeof(char*)*(nfiles+1));
+    p= findoutput.buf; i=0;
+    while (*p) {
+      arglist[i++]= p;
+      while ((c= *p++) != 0);
+    }
+    arglist[i]= 0;
+    argp= arglist;
+
+  } else {
+
+    if (!*argv) badusage("--%s needs at least one package archive file argument",
+                         cipaction->olong);
+    argp= argv;
+    
+  }
+
+  modstatdb_init(admindir,
+                 f_noact ?                     msdbrw_readonly
+               : cipaction->arg == act_avail ? msdbrw_write
+               :                               msdbrw_needsuperuser);
+
+  currenttime= time(0);
+
+  varbufaddstr(&fnamevb,instdir); varbufaddc(&fnamevb,'/');
+  varbufaddstr(&fnametmpvb,instdir); varbufaddc(&fnametmpvb,'/');
+  varbufaddstr(&fnamenewvb,instdir); varbufaddc(&fnamenewvb,'/');
+  fnameidlu= fnamevb.used;
+
+  ensure_diversions();
+  
+  while ((thisarg= *argp++) != 0) {
+    if (setjmp(ejbuf)) {
+      error_unwind(ehflag_bombout);
+      if (onerr_abort > 0) break;
+      continue;
+    }
+    push_error_handler(&ejbuf,print_error_perpackage,thisarg);
+    process_archive(thisarg);
+    onerr_abort++;
+    if (ferror(stdout)) werr("stdout");
+    if (ferror(stderr)) werr("stderr");
+    onerr_abort--;
+    set_error_display(0,0);
+    error_unwind(ehflag_normaltidy);
+  }
+
+  switch (cipaction->arg) {
+  case act_install:
+  case act_configure:
+  case act_remove:
+  case act_purge:
+    process_queue();
+  case act_unpack:
+  case act_avail:
+    break;
+  default:
+    internerr("unknown action");
+  }
+
+  modstatdb_shutdown();
+}
diff --git a/main/archives.h b/main/archives.h
new file mode 100644 (file)
index 0000000..00babbe
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * dpkg - main program for package management
+ * archives.h - functions common to archives.c and processarc.c
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef ARCHIVES_H
+#define ARCHIVES_H
+
+struct tarcontext {
+  FILE *backendpipe;
+  struct pkginfo *pkg;
+  struct fileinlist **newfilesp;
+};
+
+extern int fnameidlu;
+extern struct varbuf fnamevb;
+extern struct varbuf fnametmpvb;
+extern struct varbuf fnamenewvb;
+extern struct packageinlist *deconfigure;
+
+void cu_pathname(int argc, void **argv);
+void cu_cidir(int argc, void **argv);
+void cu_fileslist(int argc, void **argv);
+void cu_backendpipe(int argc, void **argv);
+
+void cu_installnew(int argc, void **argv);
+
+void cu_prermupgrade(int argc, void **argv);
+void cu_prerminfavour(int argc, void **argv);
+void cu_preinstverynew(int argc, void **argv);
+void cu_preinstnew(int argc, void **argv);
+void cu_preinstupgrade(int argc, void **argv);
+void cu_postrmupgrade(int argc, void **argv);
+
+void cu_prermdeconfigure(int argc, void **argv);
+void ok_prermdeconfigure(int argc, void **argv);
+
+void setupfnamevbs(const char *filename);
+int unlinkorrmdir(const char *filename);
+
+int tarobject(struct TarInfo *ti);
+int tarfileread(void *ud, char *buf, int len);
+
+void check_conflict(struct dependency *dep, struct pkginfo *pkg,
+                    const char *pfilename, struct pkginfo **conflictorp);
+
+extern int cleanup_pkg_failed, cleanup_conflictor_failed;
+
+#endif /* ARCHIVES_H */
diff --git a/main/archtable.inc b/main/archtable.inc
new file mode 100644 (file)
index 0000000..4a57a0b
--- /dev/null
@@ -0,0 +1,8 @@
+  { "i386",    "i386" },
+  { "i486",    "i386" },
+  { "i586",    "i386" },
+  { "sparc",   "sparc" },
+  { "alpha",   "alpha" },
+  { "m68k",    "m68k" },
+  { "arm",     "arm" },
+  { "ppc",     "ppc" },
diff --git a/main/cleanup.c b/main/cleanup.c
new file mode 100644 (file)
index 0000000..b12e3cf
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * dpkg - main program for package management
+ * cleanup.c - cleanup functions, used when we need to unwind
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <assert.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+#include "tarfn.h"
+
+#include "filesdb.h"
+#include "main.h"
+#include "archives.h"
+
+int cleanup_pkg_failed=0, cleanup_conflictor_failed=0;
+
+void cu_installnew(int argc, void **argv) {
+  /* Something went wrong and we're undoing.
+   * We have the following possible situations for non-conffiles:
+   *   <foo>.dpkg-tmp exists - in this case we want to remove
+   *    <foo> if it exists and replace it with <foo>.dpkg-tmp.
+   *    This undoes the backup operation.  We also make sure
+   *    we delete <foo>.dpkg-new in case that's still hanging around.
+   *   <foo>.dpkg-tmp does not exist - in this case we haven't
+   *     got as far as creating it (or there wasn't an old version).
+   *     In this case we just delete <foo>.dpkg-new if it exists,
+   *     as it may be a half-extracted thing.
+   * For conffiles, we simply delete <foo>.dpkg-new.  For these,
+   * <foo>.dpkg-tmp shouldn't exist, as we don't make a backup
+   * at this stage.  Just to be on the safe side, though, we don't
+   * look for it.
+   */
+  struct fileinlist *nifd= (struct fileinlist*)argv[0];
+  struct filenamenode *namenode;
+  struct stat stab;
+
+  cleanup_pkg_failed++; cleanup_conflictor_failed++;
+  
+  namenode= nifd->namenode;
+  debug(dbg_eachfile,"cu_installnew `%s' flags=%o",namenode->name,namenode->flags);
+        
+  setupfnamevbs(namenode->name);
+  
+  if (!(namenode->flags & fnnf_new_conff) && !lstat(fnametmpvb.buf,&stab)) {
+    /* OK, <foo>.dpkg-tmp exists.  Remove <foo> and
+     * restore <foo>.dpkg-tmp ...
+     */
+    if (namenode->flags & fnnf_no_atomic_overwrite) {
+      /* If we can't do an atomic overwrite we have to delete first any
+       * link to the new version we may have created.
+       */
+      debug(dbg_eachfiledetail,"cu_installnew restoring nonatomic");
+      if (unlinkorrmdir(fnamevb.buf) && errno != ENOENT && errno != ENOTDIR)
+        ohshite("unable to remove newly-installed version of `%.250s' to allow"
+                " reinstallation of backup copy",namenode->name);
+    } else {
+      debug(dbg_eachfiledetail,"cu_installnew restoring atomic");
+    }
+    /* Either we can do an atomic restore, or we've made room: */
+    if (rename(fnametmpvb.buf,fnamevb.buf))
+      ohshite("unable to restore backup version of `%.250s'",namenode->name);
+  } else {
+    debug(dbg_eachfiledetail,"cu_installnew not restoring");
+  }
+  /* Whatever, we delete <foo>.dpkg-new now, if it still exists. */
+  if (unlinkorrmdir(fnamenewvb.buf) && errno != ENOENT && errno != ENOTDIR)
+    ohshite("unable to remove newly-extracted version of `%.250s'",namenode->name);
+
+  cleanup_pkg_failed--; cleanup_conflictor_failed--;
+}
+
+void cu_prermupgrade(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_installed(pkg,POSTINSTFILE,"post-installation",
+                              "abort-upgrade",
+                              versiondescribe(pkg->available.version,
+                                              pkg->available.revision),
+                              (char*)0);
+  pkg->status= stat_installed;
+  pkg->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(pkg);
+  cleanup_pkg_failed--;
+}
+
+void ok_prermdeconfigure(int argc, void **argv) {
+  struct pkginfo *deconf= (struct pkginfo*)argv[0];
+  /* also has conflictor in argv[1] and infavour in argv[2] */
+  
+  if (cipaction->arg == act_install)
+    add_to_queue(deconf);
+}
+
+void cu_prermdeconfigure(int argc, void **argv) {
+  struct pkginfo *deconf= (struct pkginfo*)argv[0];
+  struct pkginfo *conflictor= (struct pkginfo*)argv[1];
+  struct pkginfo *infavour= (struct pkginfo*)argv[2];
+
+  maintainer_script_installed(deconf,POSTINSTFILE,"post-installation",
+                              "abort-deconfigure", "in-favour", infavour->name,
+                              versiondescribe(infavour->available.version,
+                                              infavour->available.revision),
+                              "removing", conflictor->name,
+                              versiondescribe(conflictor->installed.version,
+                                              conflictor->installed.revision),
+                              (char*)0);
+  deconf->status= stat_installed;
+  modstatdb_note(deconf);
+}
+
+void cu_prerminfavour(int argc, void **argv) {
+  struct pkginfo *conflictor= (struct pkginfo*)argv[0];
+  struct pkginfo *infavour= (struct pkginfo*)argv[1];
+
+  if (cleanup_conflictor_failed++) return;
+  maintainer_script_installed(conflictor,POSTINSTFILE,"post-installation",
+                              "abort-remove", "in-favour", infavour->name,
+                              versiondescribe(infavour->available.version,
+                                              infavour->available.revision),
+                              (char*)0);
+  conflictor->status= stat_installed;
+  conflictor->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(conflictor);
+  cleanup_conflictor_failed--;
+}
+
+void cu_preinstverynew(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+  char *cidir= (char*)argv[1];
+  char *cidirrest= (char*)argv[2];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_new(POSTRMFILE,"post-removal",cidir,cidirrest,
+                        "abort-install",(char*)0);
+  pkg->status= stat_notinstalled;
+  pkg->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(pkg);
+  cleanup_pkg_failed--;
+}
+
+void cu_preinstnew(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+  char *cidir= (char*)argv[1];
+  char *cidirrest= (char*)argv[2];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_new(POSTRMFILE,"post-removal",cidir,cidirrest,
+                        "abort-install", versiondescribe(pkg->installed.version,
+                                                         pkg->installed.revision),
+                        (char*)0);
+  pkg->status= stat_configfiles;
+  pkg->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(pkg);
+  cleanup_pkg_failed--;
+}
+
+void cu_preinstupgrade(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+  char *cidir= (char*)argv[1];
+  char *cidirrest= (char*)argv[2];
+  enum pkgstatus *oldstatusp= (enum pkgstatus*)argv[3];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_new(POSTRMFILE,"post-removal",cidir,cidirrest,
+                        "abort-upgrade",
+                        versiondescribe(pkg->installed.version,
+                                        pkg->installed.revision),
+                        (char*)0);
+  pkg->status= *oldstatusp;
+  pkg->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(pkg);
+  cleanup_pkg_failed--;
+}
+
+void cu_postrmupgrade(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_installed(pkg,PREINSTFILE,"pre-installation",
+                              "abort-upgrade", versiondescribe(pkg->available.version,
+                                                               pkg->available.revision),
+                              (char*)0);
+  cleanup_pkg_failed--;
+}
+
+void cu_prermremove(int argc, void **argv) {
+  struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+  if (cleanup_pkg_failed++) return;
+  maintainer_script_installed(pkg,POSTINSTFILE,"post-installation",
+                              "abort-remove", (char*)0);
+  pkg->status= stat_installed;
+  pkg->eflag &= ~eflagf_reinstreq;
+  modstatdb_note(pkg);
+  cleanup_pkg_failed--;
+}
diff --git a/main/configure.c b/main/configure.c
new file mode 100644 (file)
index 0000000..6ec20cf
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * dpkg - main program for package management
+ * configure.c - configure packages
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+int conffoptcells[2][2]= { CONFFOPTCELLS };
+
+static void md5hash(struct pkginfo *pkg, char hashbuf[MD5HASHLEN+1], const char *fn);
+
+void deferred_configure(struct pkginfo *pkg) {
+  /* The algorithm for deciding what to configure first is as follows:
+   * Loop through all packages doing a `try 1' until we've been round
+   * and nothing has been done, then do `try 2' and `try 3' likewise.
+   * The incrementing of `dependtry' is done by process_queue().
+   * Try 1:
+   *  Are all dependencies of this package done ?  If so, do it.
+   *  Are any of the dependencies missing or the wrong version ?
+   *   If so, abort (unless --force-depends, in which case defer)
+   *  Will we need to configure a package we weren't given as an
+   *   argument ?  If so, abort - except if --force-configure-any,
+   *   in which case we add the package to the argument list.
+   *  If none of the above, defer the package.
+   * Try 2:
+   *  Find a cycle and break it (see above).
+   *  Do as for try 1.
+   * Try 3 (only if --force-depends-version).
+   *  Same as for try 2, but don't mind version number in dependencies.
+   * Try 4 (only if --force-depends).
+   *  Do anyway.
+   */
+  struct varbuf aemsgs, cdr, cdr2;
+  char *cdr2rest;
+  int ok, r, useredited, distedited, c, cc, status, c1;
+  struct conffile *conff;
+  char currenthash[MD5HASHLEN+1], newdisthash[MD5HASHLEN+1];
+  struct stat stab;
+  enum conffopt what;
+  const char *s;
+  
+  if (pkg->status == stat_notinstalled)
+    ohshit("no package named `%s' is installed, cannot configure",pkg->name);
+  if (pkg->status != stat_unpacked && pkg->status != stat_halfconfigured)
+    ohshit("package %.250s is not ready for configuration\n"
+           " cannot configure (current status `%.250s')",
+           pkg->name, statusinfos[pkg->status].name);
+  
+  if (dependtry > 1) { if (findbreakcycle(pkg,0)) sincenothing= 0; }
+
+  varbufinit(&aemsgs);
+  ok= dependencies_ok(pkg,0,&aemsgs);
+  if (ok == 1) {
+    varbuffree(&aemsgs);
+    pkg->clientdata->istobe= itb_installnew;
+    add_to_queue(pkg);
+    return;
+  } else if (ok == 0) {
+    sincenothing= 0;
+    varbufaddc(&aemsgs,0);
+    fprintf(stderr,
+            DPKG ": dependency problems prevent configuration of %s:\n%s",
+            pkg->name, aemsgs.buf);
+    varbuffree(&aemsgs);
+    ohshit("dependency problems - leaving unconfigured");
+  } else if (aemsgs.used) {
+    varbufaddc(&aemsgs,0);
+    fprintf(stderr,
+            DPKG ": %s: dependency problems, but configuring anyway as you request:\n%s",
+            pkg->name, aemsgs.buf);
+  }
+  varbuffree(&aemsgs);
+  sincenothing= 0;
+
+  if (pkg->eflag & eflagf_reinstreq)
+    forcibleerr(fc_removereinstreq,
+                "Package is in a very bad inconsistent state - you should\n"
+                " reinstall it before attempting configuration.");
+
+  printf("Setting up %s ...\n",pkg->name);
+
+  if (f_noact) {
+    pkg->status= stat_installed;
+    pkg->clientdata->istobe= itb_normal;
+    return;
+  }
+  
+  if (pkg->status == stat_unpacked) {
+    debug(dbg_general,"deferred_configure updating conffiles");
+
+    /* This will not do at all the right thing with overridden conffiles
+     * or conffiles that are the `target' of an override; all the references
+     * here would be to the `contested' filename, and in any case there'd
+     * only be one hash for both `versions' of the conffile.
+     *
+     * Overriding conffiles is a silly thing to do anyway :-).
+     */
+
+    modstatdb_note(pkg);
+
+    /* On entry, the `new' version of each conffile has been
+     * unpacked as *.dpkg-new, and the `installed' version is
+     * as-yet untouched in `*'.  The hash of the `old distributed'
+     * version is in the conffiles data for the package.
+     * If `*.dpkg-new' no longer exists we assume that we've already
+     * processed this one.
+     */
+    varbufinit(&cdr);
+    varbufinit(&cdr2);
+    for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
+      r= conffderef(pkg, &cdr, conff->name);
+      if (r == -1) {
+        conff->hash= nfstrsave("-");
+        continue;
+      }
+      md5hash(pkg,currenthash,cdr.buf);
+
+      varbufreset(&cdr2);
+      varbufaddstr(&cdr2,cdr.buf);
+      cdr2.used+=50; varbufaddc(&cdr2,0); cdr2rest= cdr2.buf+strlen(cdr.buf);
+      /* From now on we can just strcpy(cdr2rest,extension); */
+
+      strcpy(cdr2rest,DPKGNEWEXT);
+      /* If the .dpkg-new file is no longer there, ignore this one. */
+      if (lstat(cdr2.buf,&stab)) {
+        if (errno == ENOENT) continue;
+        ohshite("unable to stat new dist conffile `%.250s'",cdr2.buf);
+      }
+      md5hash(pkg,newdisthash,cdr2.buf);
+
+      /* Copy the permissions from the installed version to the new
+       * distributed version.
+       */
+      if (!stat(cdr.buf,&stab)) {
+        if (chown(cdr2.buf,stab.st_uid,stab.st_gid))
+          ohshite("unable to change ownership of new dist conffile `%.250s'",cdr2.buf);
+        if (chmod(cdr2.buf,stab.st_mode & 07777))
+          if (errno != ENOENT)
+            ohshite("unable to set mode of new dist conffile `%.250s'",cdr2.buf);
+      } else {
+        if (errno != ENOENT)
+          ohshite("unable to stat current installed conffile `%.250s'",cdr.buf);
+      }
+
+      if (!strcmp(currenthash,newdisthash)) {
+        /* They're both the same so there's no point asking silly questions. */
+        useredited= -1;
+        distedited= -1;
+        what= cfo_identical;
+      } else if (!strcmp(conff->hash,NEWCONFFILEFLAG)) {
+        if (!strcmp(currenthash,NONEXISTENTFLAG)) {
+          what= cfo_newconff;
+          useredited= -1;
+          distedited= -1;
+        } else {
+          useredited= 1;
+          distedited= 1;
+          what= conffoptcells[useredited][distedited] | cfof_isnew;
+        }
+      } else {
+        useredited= strcmp(conff->hash,currenthash) != 0;
+        distedited= strcmp(conff->hash,newdisthash) != 0;
+        what= conffoptcells[useredited][distedited];
+      }
+
+      debug(dbg_conff,
+            "deferred_configure `%s' (= `%s') useredited=%d distedited=%d what=%o",
+            conff->name, cdr.buf, useredited, distedited, what);
+      
+      if (what & cfof_prompt) {
+
+        do {
+          
+          fprintf(stderr, "\nConfiguration file `%s'", conff->name);
+          if (strcmp(conff->name,cdr.buf))
+            fprintf(stderr," (actually `%s')",cdr.buf);
+
+          if (cfof_isnew) {
+
+            fprintf(stderr,
+                    "\n"
+                    " ==> File on system created by you or by a script.\n"
+                    " ==> File also in package provided by package maintainer.\n");
+
+          } else {
+            
+            fprintf(stderr, useredited ?
+                    "\n ==> Modified (by you or by a script) since installation.\n" :
+                    "\n     Not modified since installation.\n");
+
+            fprintf(stderr, distedited ?
+                    " ==> Package distributor has shipped an updated version.\n" :
+                    "     Version in package is the same as at last installation.\n");
+
+          }
+          
+          fprintf(stderr,
+                  "   What would you like to do about it ?  Your options are:\n"
+                  "    Y or I  : install the package maintainer's version\n"
+                  "    N or O  : keep your currently-installed version\n"
+                  "      Z     : background this process to examine the situation\n");
+
+          if (what & cfof_keep)
+            fprintf(stderr, " The default action is to keep your current version.\n");
+          else if (what & cfof_install)
+            fprintf(stderr, " The default action is to install the new version.\n");
+
+          s= strrchr(conff->name,'/');
+          if (!s || !*++s) s= conff->name;
+          fprintf(stderr, "*** %s (Y/I/N/O/Z) %s ? ",
+                  s,
+                  (what & cfof_keep) ? "[default=N]" :
+                  (what & cfof_install) ? "[default=Y]" : "[no default]");
+
+          if (ferror(stderr))
+            ohshite("error writing to stderr, discovered before conffile prompt");
+
+          cc= 0;
+          while ((c= getchar()) != EOF && c != '\n')
+            if (!isspace(c) && !cc) cc= tolower(c);
+
+          if (c == EOF) {
+            if (ferror(stdin)) ohshite("read error on stdin at conffile prompt");
+            ohshit("EOF on stdin at conffile prompt");
+          }
+
+          if (!cc) {
+            if (what & cfof_keep) { cc= 'n'; break; }
+            else if (what & cfof_install) { cc= 'y'; break; }
+          }
+          
+          /* fixme: say something if silently not install */
+
+          if (cc == 'z') {
+
+            strcpy(cdr2rest, DPKGNEWEXT);
+            
+            fprintf(stderr,
+          "Your currently installed version of the file is in:\n"
+          " %s\n"
+          "The version contained in the new version of the package is in:\n"
+          " %s\n"
+          "If you decide to take care of the update yourself, perhaps by editing\n"
+          " the installed version, you should choose `N' when you return, so that\n"
+          " I do not mess up your careful work.\n",
+                    cdr.buf, cdr2.buf);
+
+            s= getenv(NOJOBCTRLSTOPENV);
+            if (s && *s) {
+              fputs("Type `exit' when you're done.\n",stderr);
+              if (!(c1= m_fork())) {
+                s= getenv(SHELLENV);
+                if (!s || !*s) s= DEFAULTSHELL;
+                execlp(s,s,"-i",(char*)0);
+                ohshite("failed to exec shell (%.250s)",s);
+              }
+              while ((r= waitpid(c1,&status,0)) == -1 && errno == EINTR);
+              if (r != c1) { onerr_abort++; ohshite("wait for shell failed"); }
+            } else {
+              fputs("Don't forget to foreground (`fg') this "
+                    "process when you're done !\n",stderr);
+              kill(-getpgid(0),SIGTSTP);
+            }
+          }
+
+        } while (!strchr("yino",cc));
+
+        switch (cc) {
+        case 'i': case 'y':  what= cfof_install | cfof_backup;   break;
+        case 'n': case 'o':  what= cfof_keep    | cfof_backup;   break;
+        default:             internerr("unknown response");
+        }
+
+      }
+
+      switch (what & ~cfof_isnew) {
+      case cfo_keep | cfof_backup:
+        strcpy(cdr2rest,DPKGOLDEXT);
+        if (unlink(cdr2.buf) && errno != ENOENT)
+          fprintf(stderr,
+                  DPKG ": %s: warning - failed to remove old backup `%.250s': %s\n",
+                  pkg->name, cdr2.buf, strerror(errno));
+        cdr.used--;
+        varbufaddstr(&cdr,DPKGDISTEXT);
+        varbufaddc(&cdr,0);
+        strcpy(cdr2rest,DPKGNEWEXT);
+        if (rename(cdr2.buf,cdr.buf))
+          fprintf(stderr,
+                  DPKG ": %s: warning - failed to rename `%.250s' to `%.250s': %s\n",
+                  pkg->name, cdr2.buf, cdr.buf, strerror(errno));
+        break;
+
+      case cfo_keep:
+        strcpy(cdr2rest,DPKGNEWEXT);
+        if (unlink(cdr2.buf))
+          fprintf(stderr,
+                  DPKG ": %s: warning - failed to remove `%.250s': %s\n",
+                  pkg->name, cdr2.buf, strerror(errno));
+        break;
+
+      case cfo_install | cfof_backup:
+        strcpy(cdr2rest,DPKGDISTEXT);
+        if (unlink(cdr2.buf) && errno != ENOENT)
+          fprintf(stderr, DPKG
+                  ": %s: warning - failed to remove old distrib version `%.250s': %s\n",
+                  pkg->name, cdr2.buf, strerror(errno));
+        strcpy(cdr2rest,DPKGOLDEXT);
+        if (unlink(cdr2.buf) && errno != ENOENT)
+          fprintf(stderr, DPKG
+                  ": %s: warning - failed to remove `%.250s' (before overwrite): %s\n",
+                  pkg->name, cdr2.buf, strerror(errno));
+        if (link(cdr.buf,cdr2.buf))
+          fprintf(stderr, DPKG
+                  ": %s: warning - failed to link `%.250s' to `%.250s': %s\n",
+                  pkg->name, cdr.buf, cdr2.buf, strerror(errno));
+        /* fall through */
+      case cfo_install:
+        printf("Installing new version of config file %s ...\n",conff->name);
+      case cfo_newconff:
+        strcpy(cdr2rest,DPKGNEWEXT);
+        if (rename(cdr2.buf,cdr.buf))
+          ohshite("unable to install `%.250s' as `%.250s'",cdr2.buf,cdr.buf);
+        break;
+
+      default:
+        internerr("unknown what");
+      }
+
+      conff->hash= nfstrsave(newdisthash);
+      modstatdb_note(pkg);
+      
+    } /* for (conff= ... */
+    varbuffree(&cdr);
+    varbuffree(&cdr2);
+
+    pkg->status= stat_halfconfigured;
+  }
+
+  assert(pkg->status == stat_halfconfigured);
+
+  modstatdb_note(pkg);
+
+  if (maintainer_script_installed(pkg, POSTINSTFILE, "post-installation",
+                                  "configure",
+                                  versiondescribe(pkg->configversion,
+                                                  pkg->configrevision),
+                                  (char*)0))
+    putchar('\n');
+
+  pkg->status= stat_installed;
+  pkg->eflag= eflagv_ok;
+  modstatdb_note(pkg);
+
+}
+
+int conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in) {
+  /* returns 0 if all OK, -1 if some kind of error. */
+  static char *linkreadbuf= 0;
+  static int linkreadbufsize= 0;
+  struct stat stab;
+  int r, need;
+  int loopprotect;
+
+  varbufreset(result);
+  varbufaddstr(result,instdir);
+  if (*in != '/') varbufaddc(result,'/');
+  varbufaddstr(result,in);
+  varbufaddc(result,0);
+
+  loopprotect= 0;
+  
+  for (;;) {
+    debug(dbg_conffdetail,"conffderef in=`%s' current working=`%s'", in, result->buf);
+    if (lstat(result->buf,&stab)) {
+      if (errno != ENOENT)
+        fprintf(stderr, DPKG ": %s: warning - unable to stat config file `%s'\n"
+                " (= `%s'): %s\n",
+                pkg->name, in, result->buf, strerror(errno));
+      debug(dbg_conffdetail,"conffderef nonexistent");
+      return 0;
+    } else if (S_ISREG(stab.st_mode)) {
+      debug(dbg_conff,"conffderef in=`%s' result=`%s'", in, result->buf);
+      return 0;
+    } else if (S_ISLNK(stab.st_mode)) {
+      debug(dbg_conffdetail,"conffderef symlink loopprotect=%d",loopprotect);
+      if (loopprotect++ >= 25) {
+        fprintf(stderr, DPKG ": %s: warning - config file `%s' is a circular link\n"
+                " (= `%s')\n", pkg->name, in, result->buf);
+        return -1;
+      }
+      need= 255;
+      for (;;) {
+        if (need > linkreadbufsize) {
+          linkreadbuf= m_realloc(linkreadbuf,need);
+          linkreadbufsize= need;
+          debug(dbg_conffdetail,"conffderef readlink realloc(%d)=%p",need,linkreadbuf);
+        }
+        r= readlink(result->buf,linkreadbuf,linkreadbufsize-1);
+        if (r < 0) {
+          fprintf(stderr, DPKG ": %s: warning - unable to readlink conffile `%s'\n"
+                  " (= `%s'): %s\n",
+                  pkg->name, in, result->buf, strerror(errno));
+          return -1;
+        }
+        debug(dbg_conffdetail,"conffderef readlink gave %d, `%.*s'",
+              r, r>0 ? r : 0, linkreadbuf);
+        if (r < linkreadbufsize-1) break;
+        need= r<<2;
+      }
+      linkreadbuf[r]= 0;
+      if (linkreadbuf[0] == '/') {
+        varbufreset(result);
+        varbufaddstr(result,instdir);
+        debug(dbg_conffdetail,"conffderef readlink absolute");
+      } else {
+        for (r=result->used-2; r>0 && result->buf[r] != '/'; r--);
+        if (r < 0) {
+          fprintf(stderr, DPKG
+                  ": %s: warning - conffile `%.250s' resolves to degenerate filename\n"
+                  " (`%s' is a symlink to `%s')\n",
+                  pkg->name, in, result->buf, linkreadbuf);
+          return -1;
+        }
+        if (result->buf[r] == '/') r++;
+        result->used= r;
+        debug(dbg_conffdetail,"conffderef readlink relative to `%.*s'",
+              result->used, result->buf);
+      }
+      varbufaddstr(result,linkreadbuf);
+      varbufaddc(result,0);
+    } else {
+      fprintf(stderr, DPKG ": %s: warning - conffile `%.250s' is not a plain"
+              " file or symlink (= `%s')\n",
+              pkg->name, in, result->buf);
+      return -1;
+    }
+  }
+}
+    
+static void md5hash(struct pkginfo *pkg, char hashbuf[33], const char *fn) {
+  static int fd, p1[2];
+  FILE *file;
+  pid_t c1;
+  int ok;
+  
+  fd= open(fn,O_RDONLY);
+  if (fd >= 0) {
+    push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,(void*)&fd);
+    m_pipe(p1);
+    push_cleanup(cu_closepipe,ehflag_bombout, 0,0, 1,(void*)&p1[0]);
+    if (!(c1= m_fork())) {
+      m_dup2(fd,0); m_dup2(p1[1],1); close(p1[0]);
+      execlp(MD5SUM,MD5SUM,(char*)0);
+      ohshite("failed to exec md5sum");
+    }
+    close(p1[1]); close(fd);
+    file= fdopen(p1[0],"r");
+    push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
+    if (!file) ohshite("unable to fdopen for md5sum of `%.250s'",fn);
+    ok= 1;
+    memset(hashbuf,0,33);
+    if (fread(hashbuf,1,32,file) != 32) ok=0;
+    if (getc(file) != '\n') ok=0;
+    if (getc(file) != EOF) ok=0;
+    waitsubproc(c1,"md5sum",0);
+    if (strspn(hashbuf,"0123456789abcdef") != 32) ok=0;
+    if (ferror(file)) ohshite("error reading pipe from md5sum");
+    if (fclose(file)) ohshite("error closing pipe from md5sum");
+    pop_cleanup(ehflag_normaltidy); /* file= fdopen(p1[0]) */
+    pop_cleanup(ehflag_normaltidy); /* m_pipe() */
+    pop_cleanup(ehflag_normaltidy); /* fd= open(cdr.buf) */
+    if (!ok) ohshit("md5sum gave malformatted output `%.250s'",hashbuf);
+  } else if (errno == ENOENT) {
+    strcpy(hashbuf,NONEXISTENTFLAG);
+  } else {
+    fprintf(stderr, DPKG ": %s: warning - unable to open conffile %s for hash: %s\n",
+            pkg->name, fn, strerror(errno));
+    strcpy(hashbuf,"-");
+  }
+}      
diff --git a/main/debugmake b/main/debugmake
new file mode 100755 (executable)
index 0000000..7c142c5
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make XCFLAGS=-g LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
diff --git a/main/depcon.c b/main/depcon.c
new file mode 100644 (file)
index 0000000..7e90464
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * dpkg - main program for package management
+ * depcon.c - dependency and conflict checking
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+#include "main.h"
+
+int versionsatisfied5(const char *itver, const char *itrev,
+                      const char *refver, const char *refrev,
+                      enum depverrel verrel) {
+  int r;
+  if (verrel == dvr_none) return 1;
+  r= versioncompare(itver,itrev,refver,refrev);
+  switch (verrel) {
+  case dvr_earlierequal:   return r <= 0;
+  case dvr_laterequal:     return r >= 0;
+  case dvr_earlierstrict:  return r < 0;
+  case dvr_laterstrict:    return r > 0;
+  case dvr_exact:          return r == 0;
+  default:                 internerr("unknown verrel");
+  }
+}
+
+int versionsatisfied(struct pkginfoperfile *it, struct deppossi *against) {
+  return versionsatisfied5(it->version, it->revision,
+                           against->version, against->revision, against->verrel);
+}
+
+const char *versiondescribe(const char *ver, const char *rev) {
+  static char bufs[10][512];
+  static int bufnum=0;
+  char *buf;
+  
+  buf= bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0;
+  
+  if (!ver || !*ver) {
+    strcpy(buf,"<unknown>");
+  } else {
+    if (rev && *rev) {
+      sprintf(buf, "%.250s-%.250s", ver, rev);
+    } else {
+      sprintf(buf, "%.250s", ver);
+    }
+  }
+  return buf;
+}
+
+struct cyclesofarlink {
+  struct cyclesofarlink *back;
+  struct pkginfo *pkg;
+  struct deppossi *possi;
+};
+
+static int foundcyclebroken(struct cyclesofarlink *thislink,
+                            struct cyclesofarlink *sofar,
+                            struct pkginfo *dependedon,
+                            struct deppossi *possi) {
+  struct cyclesofarlink *sol;
+  const char *postinstfilename;
+  struct stat stab;
+
+  /* We're investigating the dependency `possi' to see if it
+   * is part of a loop.  To this end we look to see whether the
+   * depended-on package is already one of the packages whose
+   * dependencies we're searching.
+   */
+  for (sol=sofar; sol && sol->pkg != dependedon; sol=sol->back);
+
+  /* If not, we do a recursive search on it to see what we find. */
+  if (!sol) return findbreakcycle(possi->ed,thislink);
+  
+  debug(dbg_depcon,"found cycle");
+  /* Right, we now break one of the links.  We prefer to break
+   * a dependency of a package without a postinst script, as
+   * this is a null operation.  If this is not possible we break
+   * the other link in the recursive calling tree which mentions
+   * this package (this being the first package involved in the
+   * cycle).  It doesn't particularly matter which we pick, but if
+   * we break the earliest dependency we came across we may be
+   * able to do something straight away when findbreakcycle returns.
+   */
+  sofar= thislink;
+  for (sol= sofar; !(sol != sofar && sol->pkg == dependedon); sol=sol->back) {
+    postinstfilename= pkgadminfile(sol->pkg,POSTINSTFILE);
+    if (lstat(postinstfilename,&stab)) {
+      if (errno == ENOENT) break;
+      ohshite("unable to check for existence of `%.250s'",postinstfilename);
+    }
+  }
+  /* Now we have either a package with no postinst, or the other
+   * occurrence of the current package in the list.
+   */
+  sol->possi->cyclebreak= 1;
+  debug(dbg_depcon,"cycle broken at %s -> %s\n",
+        sol->possi->up->up->name, sol->possi->ed->name);
+  return 1;
+}
+
+int findbreakcycle(struct pkginfo *pkg, struct cyclesofarlink *sofar) {
+  /* Cycle breaking works recursively down the package dependency
+   * tree.  `sofar' is the list of packages we've descended down
+   * already - if we encounter any of its packages again in a
+   * dependency we have found a cycle.
+   */
+  struct cyclesofarlink thislink, *sol;
+  struct dependency *dep;
+  struct deppossi *possi, *providelink;
+  struct pkginfo *provider;
+
+  if (f_debug & dbg_depcondetail) {
+    fprintf(stderr,"D0%05o: findbreakcycle %s ",dbg_depcondetail,pkg->name);
+    for (sol=sofar; sol; sol=sol->back) fprintf(stderr," <- %s",sol->pkg->name);
+    fprintf(stderr,"\n");
+  }
+  thislink.pkg= pkg;
+  thislink.back= sofar;
+  thislink.possi= 0;
+  for (dep= pkg->installed.depends; dep; dep= dep->next) {
+    if (dep->type != dep_depends && dep->type != dep_predepends) continue;
+    for (possi= dep->list; possi; possi= possi->next) {
+      /* We can't have any cycles involving packages we're not trying
+       * to do anything with.
+       */
+      if (possi->ed->clientdata->istobe == itb_normal) continue;
+      /* Don't find the same cycles again. */
+      if (possi->cyclebreak) continue;
+      thislink.possi= possi;
+      if (foundcyclebroken(&thislink,sofar,possi->ed,possi)) return 1;
+      /* Right, now we try all the providers ... */
+      for (providelink= possi->ed->installed.depended;
+           providelink;
+           providelink= providelink->nextrev) {
+        if (providelink->up->type != dep_provides) continue;
+        provider= providelink->up->up;
+        if (provider->clientdata->istobe == itb_normal) continue;
+        /* We don't break things at `provides' links, so `possi' is
+         * still the one we use.
+         */
+        if (foundcyclebroken(&thislink,sofar,provider,possi)) return 1;
+      }
+    }
+  }
+  /* Nope, we didn't find a cycle to break. */
+  return 0;
+}
+
+void describedepcon(struct varbuf *addto, struct dependency *dep) {
+  varbufaddstr(addto,dep->up->name);
+  switch (dep->type) {
+  case dep_depends:     varbufaddstr(addto, " depends on ");     break;
+  case dep_predepends:  varbufaddstr(addto, " pre-depends on "); break;
+  case dep_recommends:  varbufaddstr(addto, " recommends ");     break;
+  case dep_conflicts:   varbufaddstr(addto, " conflicts with "); break;
+  default:              internerr("unknown deptype");
+  }
+  varbufdependency(addto, dep);
+}
+  
+int depisok(struct dependency *dep, struct varbuf *whynot,
+            struct pkginfo **canfixbyremove, int allowunconfigd) {
+  /* *whynot must already have been initialised; it need not be
+   * empty though - it will be reset before use.
+   * If depisok returns 0 for `not OK' it will contain a description,
+   * newline-terminated BUT NOT NULL-TERMINATED, of the reason.
+   * If depisok returns 1 it will contain garbage.
+   * allowunconfigd should be non-zero during the `Pre-Depends' checking
+   * before a package is unpacked, when it is sufficient for the package
+   * to be unpacked provided that both the unpacked and previously-configured
+   * versions are acceptable.
+   */
+  struct deppossi *possi;
+  struct deppossi *provider;
+  int nconflicts;
+
+  /* Use this buffer so that when internationalisation comes along we
+   * don't have to rewrite the code completely, only redo the sprintf strings
+   * (assuming we have the fancy argument-number-specifiers).
+   * Allow 250x3 for package names, versions, &c, + 250 for ourselves.
+   */
+  char linebuf[1024];
+
+  assert(dep->type == dep_depends || dep->type == dep_predepends ||
+         dep->type == dep_conflicts || dep->type == dep_recommends);
+  
+  /* The dependency is always OK if we're trying to remove the depend*ing*
+   * package.
+   */
+  switch (dep->up->clientdata->istobe) {
+  case itb_remove: case itb_deconfigure:
+    return 1;
+  case itb_normal:
+    /* Only `installed' packages can be make dependency problems */
+    switch (dep->up->status) {
+    case stat_installed:
+      break;
+    case stat_notinstalled: case stat_configfiles: case stat_halfinstalled:
+    case stat_halfconfigured: case stat_unpacked:
+      return 1;
+    default:
+      internerr("unknown status depending");
+    }
+    break;
+  case itb_installnew: case itb_preinstall:
+    break;
+  default:
+    internerr("unknown istobe depending");
+  }
+
+  /* Describe the dependency, in case we have to moan about it. */
+  varbufreset(whynot);
+  varbufaddc(whynot, ' ');
+  describedepcon(whynot, dep);
+  varbufaddc(whynot,'\n');
+  
+  if (dep->type == dep_depends || dep->type == dep_predepends ||
+      dep->type == dep_recommends) {
+    
+    /* Go through the alternatives.  As soon as we find one that
+     * we like, we return `1' straight away.  Otherwise, when we get to
+     * the end we'll have accumulated all the reasons in whynot and
+     * can return `0'.
+     */
+    
+    for (possi= dep->list; possi; possi= possi->next) {
+      switch (possi->ed->clientdata->istobe) {
+      case itb_remove:
+        sprintf(linebuf, "  %.250s is to be removed.\n", possi->ed->name);
+        break;
+      case itb_deconfigure:
+        sprintf(linebuf, "  %.250s is to be deconfigured.\n", possi->ed->name);
+        break;
+      case itb_installnew:
+        if (versionsatisfied(&possi->ed->available, possi)) return 1;
+        sprintf(linebuf, "  %.250s is to be installed, but is version %.250s.\n",
+                possi->ed->name,
+                versiondescribe(possi->ed->available.version,
+                                possi->ed->available.revision));
+        break;
+      case itb_normal: case itb_preinstall:
+        switch (possi->ed->status) {
+        case stat_installed:
+          if (versionsatisfied(&possi->ed->installed, possi)) return 1;
+          sprintf(linebuf, "  %.250s is installed, but is version %.250s.\n",
+                  possi->ed->name,
+                  versiondescribe(possi->ed->available.version,
+                                  possi->ed->available.revision));
+          break;
+        case stat_notinstalled:
+          /* Don't say anything about this yet - it might be a virtual package.
+           * Later on, if nothing has put anything in linebuf, we know that it
+           * isn't and issue a diagnostic then.
+           */
+          *linebuf= 0;
+          break;
+        case stat_unpacked:
+        case stat_halfconfigured:
+          if (allowunconfigd) {
+            if (!possi->ed->configversion || !*possi->ed->configversion) {
+              sprintf(linebuf, "  %.250s is unpacked, but has never been configured.\n",
+                      possi->ed->name);
+              break;
+            } else if (!versionsatisfied(&possi->ed->installed, possi)) {
+              sprintf(linebuf, "  %.250s is unpacked, but is version %.250s.\n",
+                      possi->ed->name,
+                      versiondescribe(possi->ed->available.version,
+                                      possi->ed->available.revision));
+              break;
+            } else if (!versionsatisfied5(possi->ed->configversion,
+                                          possi->ed->configrevision,
+                                          possi->version, possi->revision,
+                                          possi->verrel)) {
+              sprintf(linebuf, "  %.250s latest configured version is %.250s.\n",
+                      possi->ed->name,
+                      versiondescribe(possi->ed->configversion,
+                                      possi->ed->configrevision));
+              break;
+            } else {
+              return 1;
+            }
+          }
+        default:
+          sprintf(linebuf, "  %.250s is %s.\n",
+                  possi->ed->name, statusstrings[possi->ed->status]);
+          break;
+        }
+        break;
+      default:
+        internerr("unknown istobe depended");
+      }
+      varbufaddstr(whynot, linebuf);
+
+      /* If there was no version specified we try looking for Providers. */
+      if (possi->verrel == dvr_none) {
+        
+        /* See if the package we're about to install Provides it. */
+        for (provider= possi->ed->available.depended;
+             provider;
+             provider= provider->nextrev) {
+          if (provider->up->type != dep_provides) continue;
+          if (provider->up->up->clientdata->istobe == itb_installnew) return 1;
+        }
+
+        /* Now look at the packages already on the system. */
+        for (provider= possi->ed->installed.depended;
+             provider;
+             provider= provider->nextrev) {
+          if (provider->up->type != dep_provides) continue;
+          
+          switch (provider->up->up->clientdata->istobe) {
+          case itb_installnew:
+            /* Don't pay any attention to the Provides field of the
+             * currently-installed version of the package we're trying
+             * to install.  We dealt with that by using the available
+             * information above.
+             */
+            continue; 
+          case itb_remove:
+            sprintf(linebuf, "  %.250s provides %.250s but is to be removed.\n",
+                    provider->up->up->name, possi->ed->name);
+            break;
+          case itb_deconfigure:
+            sprintf(linebuf, "  %.250s provides %.250s but is to be deconfigured.\n",
+                    provider->up->up->name, possi->ed->name);
+            break;
+          case itb_normal: case itb_preinstall:
+            if (provider->up->up->status == stat_installed) return 1;
+            sprintf(linebuf, "  %.250s provides %.250s but is %s.\n",
+                    provider->up->up->name, possi->ed->name,
+                    statusstrings[provider->up->up->status]);
+            break;
+          default:
+            internerr("unknown istobe provider");
+          }
+          varbufaddstr(whynot, linebuf);
+        }
+        
+        if (!*linebuf) {
+          /* If the package wasn't installed at all, and we haven't said
+           * yet why this isn't satisfied, we should say so now.
+           */
+          sprintf(linebuf, "  %.250s is not installed.\n", possi->ed->name);
+          varbufaddstr(whynot, linebuf);
+        }
+      }
+    }
+
+    if (canfixbyremove) *canfixbyremove= 0;
+    return 0;
+
+  } else {
+    
+    /* It's a conflict.  There's only one main alternative,
+     * but we also have to consider Providers.  We return `0' as soon
+     * as we find something that matches the conflict, and only describe
+     * it then.  If we get to the end without finding anything we return `1'.
+     */
+
+    possi= dep->list;
+    nconflicts= 0;
+
+    if (possi->ed != possi->up->up) {
+      /* If the package conflicts with itself it must mean that it conflicts
+       * with other packages which provide the same virtual name.  We therefore
+       * don't look at the real package and go on to the virtual ones.
+       */
+      
+      switch (possi->ed->clientdata->istobe) {
+      case itb_remove:
+        break;
+      case itb_installnew:
+        if (!versionsatisfied(&possi->ed->available, possi)) break;
+        sprintf(linebuf, "  %.250s (version %.250s) is to be installed.\n",
+                possi->ed->name,
+                versiondescribe(possi->ed->available.version,
+                                possi->ed->available.revision));
+        varbufaddstr(whynot, linebuf);
+        if (!canfixbyremove) return 0;
+        nconflicts++;
+        *canfixbyremove= possi->ed;
+        break;
+      case itb_normal: case itb_deconfigure: case itb_preinstall:
+        switch (possi->ed->status) {
+        case stat_notinstalled: case stat_configfiles:
+          break;
+        default:
+          if (!versionsatisfied(&possi->ed->installed, possi)) break;
+          sprintf(linebuf, "  %.250s (version %.250s) is %s.\n",
+                  possi->ed->name,
+                  versiondescribe(possi->ed->available.version,
+                                  possi->ed->available.revision),
+                  statusstrings[possi->ed->status]);
+          varbufaddstr(whynot, linebuf);
+          if (!canfixbyremove) return 0;
+          nconflicts++;
+          *canfixbyremove= possi->ed;
+        }
+        break;
+      default:
+        internerr("unknown istobe conflict");
+      }
+    }
+
+    /* If there was no version specified we try looking for Providers. */
+    if (possi->verrel == dvr_none) {
+        
+      /* See if the package we're about to install Provides it. */
+      for (provider= possi->ed->available.depended;
+           provider;
+           provider= provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+        if (provider->up->up->clientdata->istobe != itb_installnew) continue;
+        if (provider->up->up == dep->up) continue; /* conflicts and provides the same */
+        sprintf(linebuf, "  %.250s provides %.250s and is to be installed.\n",
+                provider->up->up->name, possi->ed->name);
+        varbufaddstr(whynot, linebuf);
+        /* We can't remove the one we're about to install: */
+        if (canfixbyremove) *canfixbyremove= 0;
+        return 0;
+      }
+
+      /* Now look at the packages already on the system. */
+      for (provider= possi->ed->installed.depended;
+           provider;
+           provider= provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+          
+        if (provider->up->up == dep->up) continue; /* conflicts and provides the same */
+        
+        switch (provider->up->up->clientdata->istobe) {
+        case itb_installnew:
+          /* Don't pay any attention to the Provides field of the
+           * currently-installed version of the package we're trying
+           * to install.  We dealt with that by using the available
+           * information above.
+           */
+          continue; 
+        case itb_remove:
+          continue;
+        case itb_normal: case itb_deconfigure: case itb_preinstall:
+          switch (provider->up->up->status) {
+          case stat_notinstalled: case stat_configfiles:
+            continue;
+          default:
+            sprintf(linebuf, "  %.250s provides %.250s and is %s.\n",
+                    provider->up->up->name, possi->ed->name,
+                    statusstrings[provider->up->up->status]);
+            varbufaddstr(whynot, linebuf);
+            if (!canfixbyremove) return 0;
+            nconflicts++;
+            *canfixbyremove= provider->up->up;
+            break;
+          }
+          break;
+        default:
+          internerr("unknown istobe conflict provider");
+        }
+      }
+    }
+
+    if (!nconflicts) return 1;
+    if (nconflicts>1) *canfixbyremove= 0;
+    return 0;
+
+  } /* if (dependency) {...} else {...} */
+}
diff --git a/main/dpkg.8 b/main/dpkg.8
new file mode 100644 (file)
index 0000000..bf760f4
--- /dev/null
@@ -0,0 +1,20 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH DPKG 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+dpkg \- Debian package installation tool
+.SH DESCRIPTION
+.B dpkg
+does not have a useful man page.  Please do not report this as a bug,
+as this has already been done many times.
+
+Instead, if you are a competent and accurate writer and are willing to
+spend the time reading the source code and writing good manpages
+please write a better man page than this one.
+
+Type
+.B dpkg \-\-help
+for a brief summary of how to use dpkg.
+
+.SH AUTHOR
+Ian Jackson <ijackson@gnu.ai.mit.edu>; tarfile extraction code
+contributed by Bruce Perens <bruce@pixar.com>.
diff --git a/main/dpkg.8-vuori b/main/dpkg.8-vuori
new file mode 100644 (file)
index 0000000..18cc4c0
--- /dev/null
@@ -0,0 +1,588 @@
+.TH dpkg 8
+.SH NAME
+dpkg - a low-level package manager for Debian GNU/Linux
+
+.SH SYNOPSIS
+
+.B dpkb
+[options] action
+
+.SH DESCRIPTION
+
+.B dpkg
+is a medium-level tool to install, build, remove and manage Debian
+GNU/Linux packages. The primary and more user-friendly front-end
+for
+.B dpkg
+is
+.B dselect(8).
+.B dpkg
+itself is totally controlled via command line parameters, whose include
+one or more options and exactly one action. The action-parameter tells
+dpkg what to do and options control the behaviour of the action in some
+way.
+
+.B dpkg
+can be also be used as a front-end to
+.B dpkg-deb.
+Actions
+.B -b
+,
+.B --build
+,
+.B -c
+,
+.B --contents
+,
+.B -I
+,
+.B --info
+,
+.B -f
+,
+.B --field
+,
+.B -e
+,
+.B --control
+,
+.B -x
+,
+.B --extract
+,
+.B -X
+,
+.B --vextract
+and
+.B --fsys-tarfile
+are
+.B dpkg-deb
+actions and if they are encountered,
+.B dpkg
+just runs
+.B dpkg-deb
+with the parameters given to it. Please refer to
+.B dpkg-deb(8)
+for information about these actions.
+
+.SS ACTIONS
+
+.TP
+.B dpkg -i | --install <package file name> ...
+Install specified packages. If
+.B --recursive
+or
+.B -R
+option is specified,
+.I <package file name>
+must refer to a directory instead.
+
+Installation consists of the following steps:
+.br
+.B 1.
+Extract the controlfiles of the new package.
+.br
+.B 2.
+If another version of the same package was installed before the
+new installation, execute
+.I prerm
+script of the old package.
+.br
+.B 3.
+Run
+.I preinst
+script, if provided by the package.
+.br
+.B 4.
+Unpack the files and at the same time, backup the old files
+so that if something goes wrong, we can restore them.
+.br
+.B 5.
+If another version of the same package was installed before
+the new installation, execute the
+.I postrm
+script of the old package. Note that this script is executed after the
+.I preinst
+script of the new package, because new files are written at the same
+time, old files are removed.
+.br
+.B 6.
+eonfigure the package. See
+.B --configure
+for detailed information about how this is done.
+.TP
+.B dpkg --unpack <package file name> ...
+Unpack package, but don't configure it. If
+.B --recursive
+or
+.B -R
+option is specified,
+.I <package file name>
+must refer to a directory instead.
+.TP
+.B dpkg --configure     <package name> ... | -a|--pending
+Reconfigure an unpacked package.
+If
+.B -a
+or
+.B --pending
+is given instead of package name, all unpacked, but unconfigured
+packages are configured.
+
+Configuring consists of the following steps:
+.br
+.B 1.
+Unpack the configuration files and at the same time, backup the old
+configuration files, so that we can restore them, if
+something goes
+wrong.
+.br
+.B 2.
+Run
+.I postinst
+script, if provided by the package.
+.TP
+.B dpkg -r|--remove | --purge <package name> ... | -a|--pending
+Remove an installed package.
+.B --purge
+removes everything, including configuration files,
+.B --remove
+removes everything, but not configuration files. (configuration files are
+the files listed in
+.I conffiles
+-control file). If
+.B -a
+or
+.B --pending
+is given instead of package name all packages unpacked, but marked to be
+removed or purged are removed or purged (in file
+.I /var/lib/dpkg/status
+).
+
+Removing of a package consists of the following steps:
+.br
+.B 1.
+Run prerm script
+.br
+.B 2.
+Remove the installed files
+.br
+.B 3.
+Run postrm script
+.br
+.TP
+.B dpkg -A | --avail <package file name> ...
+Update 
+.B dpkg
+and
+.B dselect's
+idea of which packages are available with information about the package
+.I <package file name>.
+If
+.B --recursive
+or
+.B -R
+option is specified,
+.I <package file name>
+must refer to a directory instead.
+.TP
+.B dpkg --update-avail | --merge-avail <Packages-file>
+Update
+.B dpkg's
+and
+.B dselect's
+idea of which packages are available. With action 
+.B --merge-avail,
+information is combined from the old information and from the
+.I <Packages-file>.
+With action
+.B --update-avail,
+old information is replaced with the information in the
+.I <Packages-file>.
+The
+.I <Packages-file>
+distributed with Debian GNU/Linux is simply named
+.I Packages.
+.TP
+.B dpkg --yet-to-unpack
+Searches for packages selected for installation, but which for some
+reason still haven't been installed.
+.TP
+.B dpkg -l|--list [<package-name-pattern> ...]
+List packages matching given pattern. If no
+.B <package-name-pattern>
+is given, list all packages in
+.I /var/lib/dpkg/available.
+Normal shell wildchars are allowed in
+.B <package-name-pattern>.
+.TP
+.B dpkg -L|--listfiles <package-name> ...
+List files installed to your system from a package
+.B <package-name>.
+However, note that files created by package-specific
+installation-scripts are not listed.
+.TP
+.B dpkg -C|--audit
+Searches for packages that have been installed only partially on your
+system.
+.B dpkg
+will suggest what to do with them to get them working.
+.TP
+.B dpkg -S|--search <filename-search-pattern> ...
+Search for a filename from installed packages. All standard shell
+wildchars can be used in the pattern.
+.TP
+.B dpkg -s|--status <package-name> ...
+Report status of specified package. This just displays the entry in from
+the installed package status database.
+.TP
+.B dpkg --help
+Display a brief help.
+.TP
+.B dpkg --licence
+Display licence of
+.B dpkg.
+.TP
+.B dpkg --version
+Display version information.
+.TP
+.B dpkg-deb-actions
+See
+.B dpkg-deb(8)
+for more information about these actions.
+
+.B dpkg -b|--build <directory> [<filename>]
+- Build a Debian GNU/Linux package.
+.br
+.B dpkg -c|--contents <filename>
+- List contents of Debian GNU/Linux package.
+.br
+.B dpkg -e|--control <filename> [<directory>]
+- Extract control-information from a package.
+.br
+.B dpkg -x|--extract <filename> <directory>
+- Extract the files contained by package.
+.br
+.B dpkg -f|--field <filename> [<control-field>...]
+- Display control field(s) of a package.
+.br
+.B dpkg --fsys-tarfile <filename>
+- Display the filesystem tar-file contained by a Debian package.
+.br
+.B dpkg -I|--info <filename> [<control-file>]
+- Show information about a package.
+.br
+.B dpkg -X|--vextract <filename> <directory>
+- Extract and display the filenames contained by a package.
+
+.SS OPTIONS
+
+.TP
+.B -B | --auto-deconfigure
+While a package is removed, there is a possibility that another
+installed package depended on the removed package. Specifying this
+option will cause automatical deconfiguration of the package which
+depended on the removed package.
+.TP
+.B -Dh | --debug=help
+Give help about debugging options.
+.TP
+.B -D<octal> | --debug=<octal>
+Set debugging on.
+.B <octal>
+is a octal number formed by bitwise-orring desired values together from
+the list below (note that these values may change in future releases).
+
+ number  description
+    1   Generally helpful progress information
+    2   Invocation and status of maintainer scripts
+   10   Output for each file processed
+  100   Lots of output for each file processed
+   20   Output for each configuration file
+  200   Lots of output for each configuration file
+   40   Dependencies and conflicts
+  400   Lots of dependencies/conflicts output
+ 1000   Lots of drivel about eg the dpkg/info dir
+ 2000   Insane amounts of drivel
+.TP
+.B --force-<things> | --no-force-<things> | --refuse-<things>
+Force or refuse (no-force and refuse stands for the same thing) to do
+some things.
+.B <things>
+is a comma separated list of things specified below:
+
+.I downgrade(*):
+Install a package, even if newer version of it is already installed.
+
+.I configure-any:
+Configure also unpacked, but unconfigured packages on whose current
+package depends on.
+
+.I remove-reinstreq:
+Remove a package, even if it's broken and marked to require
+reinstallation. This may, for example, cause parts of the package to
+remain on the system, which will then be forgotten by
+.B dpkg.
+
+.I hold:
+Don't care, wheter a package is on hold or not.
+
+.I remove-essential:
+Remove, even if the package is considered essential. Essential packages
+contains mostly very basic unix commands and such. Removing them might
+cause the whole system to stop working, so use with caution.
+
+.I conflicts:
+Install, even if it conflicts with another package. This is dangerous,
+for it will usually cause overwriting of some files.
+
+.I depends:
+Remove, even if another package depends on this one. This will usually
+break the other package.
+
+.I depends-version:
+Don't care about versions when checking depencies. This will usually
+break the other package.
+
+Things marked with (*) are forced by default.
+.I Warning:
+These options are mostly intended to be used by experts only. Using them
+without fully understanding their effects may break your whole system.
+
+.TP
+.B --ignore-depends=<package>,...
+Ignore depency-checking for specified packages (actually, checking is
+performed, but only warnings about conflicts are given, nothing else).
+.TP
+.B --largemem | --smallmem
+Tells
+.B dpkg
+wheter to preserve memory or consume it as much as needed.
+.TP
+.B --new | --old
+Select new or old package format. This is a
+.B dpkg-deb(8)
+option.
+.TP
+.B --nocheck
+Don't read or check contents of control file while building a package.
+This is a
+.B dpkg-deb(8)
+option.
+.TP
+.B --no-act
+Do everything, which is supposed to be done, but don't write any
+changes. This is used to see, what would happen with specified action,
+without actually modifying anything.
+
+Be sure to give
+.B --no-act
+before action-parameter, or you might end up with undesirable results.
+(e.g.
+.B dpkg --purge foo --no-act
+will first purge package foo and then try to purge package --no-act,
+even though you propably expected it to actually do nothing)
+.TP
+.B -R | --recursive
+Recursively handle all regular files matching pattern
+.I *.deb
+found at specified directories and all of its subdirectories. This
+can be used with 
+.B -i
+,
+.B -A
+,
+.B --install
+,
+.B --unpack
+and
+.B --avail
+actions.
+.TP
+.B -G
+Don't install package, if newer version of the same package is already
+installed. This is an alias to 
+.B--refuse-downgrade.
+.TP
+.B -R|--root=<dir> | --admindir=<dir> | --instdir=<dir>
+Change default directories.
+.B admindir
+defaults to
+.I /var/lib/dpkg
+and contains many files that give information about status of installed
+or uninstalled packages, etc.
+.B instdir
+defaults to
+.I /
+and refers to the directory where packages are to be installed.
+.B instdir
+is also the directory passed to
+.B chroot(2)
+before running package's installation scripts, which means that the
+scripts see
+.B instdir
+as a root directory.
+Changing
+.B root
+changes
+.B instdir
+to
+.I <dir>
+and
+.B admindir
+to
+.I <dir>/var/lib/dpkg.
+.TP
+.B -O | --selected-only
+Only process the packages that are selected for installation. The actual
+marking is done with
+.B dselect
+or by
+.B dpkg,
+when it handles packages. i.e. When, for example a package is removed,
+it will be marked selected for installation, etc.
+.TP
+.B -E | --skip-same-version
+Don't install the package, if the same version of the package is already
+installed.
+
+.SH INFORMATION ABOUT PACKAGES
+.B dpkg
+maintains some usable information about available packages. The
+information is divided in three classes:
+.B states
+,
+.B selection states
+and
+.B flags.
+These values are intended to be changed mainly with
+.B dselect.
+.SS PACKAGE STATES
+.TP
+.B installed
+The package is unpacked and configured ok.
+.TP
+.B half-installed
+The installation of the package has been started, but not completed for
+some reason.
+.TP
+.B not-installed
+The package is not installed on your system.
+.TP
+.B unpacked
+The package is unpacked, but not configured.
+.TP
+.B half-configured
+The package is unpacked and configuration has been started, but not yet
+completed for some reason.
+.TP
+.B config-files
+Only the configuration files of the package exist on the system.
+.SS PACKAGE SELECTION STATES
+.TP
+.B install
+The package is selected for installation.
+.TP
+.B deinstall
+The package is selected for deinstallation (i.e. we want to remove all
+files, except configuration files).
+.TP
+.B purge
+The package is selected to be purged (i.e. we want to remove everything,
+even configuration files).
+.SS PACKAGE FLAGS
+.TP
+.B hold
+A package marked to be on
+.B hold
+is not handled by
+.B dpkg,
+unless forced to do that with option
+.B --force-hold.
+.TP
+.B reinst-required
+A package marked
+.B reinst-required
+is broken and requires reinstallation. These packages cannot be removed,
+unless forced with option
+.B --force-reinstreq.
+
+.SH FILES
+The files listed here are in their default directories, see option
+.B --admindir
+to see how to change locations of these files.
+.TP
+.I /var/lib/dpkg/available
+List of available packages.
+.TP
+.I /var/lib/dpkg/status
+Statuses of available packages. This file contains information about
+wheter a package is marked for removing or not, wheter it is installed
+or not, etc. See section
+.B INFORMATION ABOUT PACKAGES
+for more info.
+.TP
+.I control
+See
+.B deb(5)
+for more information about this file.
+.TP
+.I conffiles
+.B dpkg.
+See
+.B deb(5)
+for more information about this file.
+.TP
+.I preinst
+See
+.B deb(5)
+for more information about this file.
+.TP
+.I postinst
+See
+.B deb(5)
+for more information about this file.
+.TP
+.I prerm
+See
+.B deb(5)
+for more information about this file.
+.TP
+.I postrm
+See
+.B deb(5)
+for more information about this file.
+
+.SH ENVIRONMENT VARIABLES
+.TP
+.B DPKG_NO_TSTP
+Define this to something, if you prefer
+.B dpkg
+starting a new shell rather than suspending
+.B dpkg,
+while doing a shell escape.
+.TP
+.B SHELL
+The program
+.B dpkg
+will execute while starting a new shell.
+
+.SH SEE ALSO
+.B deb(5)
+,
+.B dpkg-deb(8)
+,
+.B dselect(8)
+and
+.B deb-control(5)
+
+.SH BUGS
+
+.B --no-act
+usually gives less information that might be helpful.
+.SH AUTHOR
+.B dpkg
+is written by Ian Jackson (ian@chiark.chu.cam.ac.uk). Manual page added
+by Juho Vuori (javuori@cc.helsinki.fi).
+
+
diff --git a/main/enquiry.c b/main/enquiry.c
new file mode 100644 (file)
index 0000000..43302bf
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * dpkg - main program for package management
+ * enquiry.c - status enquiry and listing options
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* fixme: per-package audit */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+static int listqcmp(const void *a, const void *b) {
+  struct pkginfo *pa= *(struct pkginfo**)a;
+  struct pkginfo *pb= *(struct pkginfo**)b;
+  return strcmp(pa->name,pb->name);
+}
+
+static void limiteddescription(struct pkginfo *pkg, int maxl,
+                               const char **pdesc_r, int *l_r) {
+  const char *pdesc, *p;
+  int l;
+  
+  pdesc= pkg->installed.valid ? pkg->installed.description : 0;
+  if (!pdesc) pdesc= "(no description available)";
+  p= strchr(pdesc,'\n');
+  if (!p) p= pdesc+strlen(pdesc);
+  l= (p - pdesc > maxl) ? maxl : (int)(p - pdesc);
+  *pdesc_r=pdesc; *l_r=l;
+}
+
+static void list1package(struct pkginfo *pkg, int *head) {
+  int l;
+  const char *pdesc;
+    
+  if (!*head) {
+    fputs("\
+Desired=Unknown/Install/Remove/Purge\n\
+| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed\n\
+|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)\n\
+||/ Name            Version        Description\n\
++++-===============-==============-============================================\n",
+          stdout);
+    *head= 1;
+  }
+  
+  if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
+  limiteddescription(pkg,44,&pdesc,&l);
+  printf("%c%c%c %-15.15s %-14.14s %.*s\n",
+         "uirp"[pkg->want],
+         "nUFiHc"[pkg->status],
+         " hRX"[pkg->eflag],
+         pkg->name,
+         versiondescribe(pkg->installed.version,pkg->installed.revision),
+         l, pdesc);
+}         
+
+void listpackages(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  struct pkginfo **pkgl;
+  const char *thisarg;
+  int np, i, head, found;
+
+  modstatdb_init(admindir,msdbrw_readonly);
+
+  np= countpackages();
+  pkgl= m_malloc(sizeof(struct pkginfo*)*np);
+  it= iterpkgstart(); i=0;
+  while ((pkg= iterpkgnext(it))) {
+    assert(i<np);
+    pkgl[i++]= pkg;
+  }
+  iterpkgend(it);
+  assert(i==np);
+
+  qsort(pkgl,np,sizeof(struct pkginfo*),listqcmp);
+  head=0;
+  
+  if (!*argv) {
+    for (i=0; i<np; i++) {
+      pkg= pkgl[i];
+      if (pkg->status == stat_notinstalled) continue;
+      list1package(pkg,&head);
+    }
+  } else {
+    while ((thisarg= *argv++)) {
+      found= 0;
+      for (i=0; i<np; i++) {
+        pkg= pkgl[i];
+        if (fnmatch(thisarg,pkg->name,0)) continue;
+        list1package(pkg,&head); found++;
+      }
+      if (!found)
+        fprintf(stderr,"No packages found matching %s.\n",thisarg);
+    }
+  }
+  if (ferror(stdout)) werr("stdout");
+  if (ferror(stderr)) werr("stderr");  
+}
+
+struct badstatinfo {
+  int (*yesno)(struct pkginfo*, const struct badstatinfo *bsi);
+  int val;
+  const char *explanation;
+};
+
+static int bsyn_reinstreq(struct pkginfo *pkg, const struct badstatinfo *bsi) {
+  return pkg->eflag &= eflagf_reinstreq;
+}
+
+static int bsyn_status(struct pkginfo *pkg, const struct badstatinfo *bsi) {
+  if (pkg->eflag &= eflagf_reinstreq) return 0;
+  return pkg->status == bsi->val;
+}
+
+static const struct badstatinfo badstatinfos[]= {
+  {
+    bsyn_reinstreq, 0,
+    "The following packages are in a mess due to serious problems during\n"
+    "installation.  They must be reinstalled for them (and any packages\n"
+    "that depend on them) to function properly:\n"
+  }, {
+    bsyn_status, stat_unpacked,
+    "The following packages have been unpacked but not yet configured.\n"
+    "They must be configured using " DPKG " --configure or the configure\n"
+    "menu option in " DSELECT " for them to work:\n"
+  }, {
+    bsyn_status, stat_halfconfigured,
+    "The following packages are only half configured, probably due to problems\n"
+    "configuring them the first time.  The configuration should be retried using\n"
+    DPKG " --configure <package> or the configure menu option in " DSELECT ":\n"
+  }, {
+    bsyn_status, stat_halfinstalled,
+    "The following packages are only half installed, due to problems during\n"
+    "installation.  The installation can probably be completed by retrying it;\n"
+    "the packages can be removed using " DSELECT " or " DPKG " --remove:\n"
+  }, {
+    0
+  }
+};
+
+static void describebriefly(struct pkginfo *pkg) {
+  int maxl, l;
+  const char *pdesc;
+
+  maxl= 57;
+  l= strlen(pkg->name);
+  if (l>20) maxl -= (l-20);
+  limiteddescription(pkg,maxl,&pdesc,&l);
+  printf(" %-20s %.*s\n",pkg->name,l,pdesc);
+}
+
+void audit(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  const struct badstatinfo *bsi;
+  int head;
+
+  if (*argv) badusage("--audit does not take any arguments");
+
+  modstatdb_init(admindir,msdbrw_readonly);
+
+  for (bsi= badstatinfos; bsi->yesno; bsi++) {
+    head= 0;
+    it= iterpkgstart(); 
+    while ((pkg= iterpkgnext(it))) {
+      if (!bsi->yesno(pkg,bsi)) continue;
+      if (!head) {
+        fputs(bsi->explanation,stdout);
+        head= 1;
+      }
+      describebriefly(pkg);
+    }
+    iterpkgend(it);
+    if (head) putchar('\n');
+  }
+  if (ferror(stderr)) werr("stderr");  
+}
+
+struct sectionentry {
+  struct sectionentry *next;
+  const char *name;
+  int count;
+};
+
+static int yettobeunpacked(struct pkginfo *pkg, const char **thissect) {
+  if (pkg->want != want_install) return 0;
+
+  switch (pkg->status) {
+  case stat_unpacked: case stat_installed: case stat_halfconfigured:
+    return 0;
+  case stat_notinstalled: case stat_halfinstalled: case stat_configfiles:
+    if (thissect)
+      *thissect= pkg->section && *pkg->section ? pkg->section : "<unknown>";
+    return 1;
+  default:
+    internerr("unknown status checking for unpackedness");
+  }
+}
+
+void unpackchk(const char *const *argv) {
+  int totalcount, sects;
+  struct sectionentry *sectionentries, *se, **sep;
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  const char *thissect;
+  char buf[20];
+  int width;
+  
+  if (*argv) badusage("--yet-to-unpack does not take any arguments");
+
+  modstatdb_init(admindir,msdbrw_readonly);
+
+  totalcount= 0;
+  sectionentries= 0;
+  sects= 0;
+  it= iterpkgstart(); 
+  while ((pkg= iterpkgnext(it))) {
+    if (!yettobeunpacked(pkg, &thissect)) continue;
+    for (se= sectionentries; se && strcasecmp(thissect,se->name); se= se->next);
+    if (!se) {
+      se= nfmalloc(sizeof(struct sectionentry));
+      for (sep= &sectionentries;
+           *sep && strcasecmp(thissect,(*sep)->name) > 0;
+           sep= &(*sep)->next);
+      se->name= thissect;
+      se->count= 0;
+      se->next= *sep;
+      *sep= se;
+      sects++;
+    }
+    se->count++; totalcount++;
+  }
+  iterpkgend(it);
+
+  if (totalcount == 0) exit(0);
+  
+  if (totalcount <= 12) {
+    it= iterpkgstart(); 
+    while ((pkg= iterpkgnext(it))) {
+      if (!yettobeunpacked(pkg,0)) continue;
+      describebriefly(pkg);
+    }
+    iterpkgend(it);
+  } else if (sects <= 12) {
+    for (se= sectionentries; se; se= se->next) {
+      sprintf(buf,"%d",se->count);
+      printf(" %d in %s: ",se->count,se->name);
+      width= 70-strlen(se->name)-strlen(buf);
+      while (width > 59) { putchar(' '); width--; }
+      it= iterpkgstart(); 
+      while ((pkg= iterpkgnext(it))) {
+        if (!yettobeunpacked(pkg,&thissect)) continue;
+        if (strcasecmp(thissect,se->name)) continue;
+        width -= strlen(pkg->name); width--;
+        if (width < 4) { printf(" ..."); break; }
+        printf(" %s",pkg->name);
+      }
+      iterpkgend(it);
+      putchar('\n');
+    }
+  } else {
+    printf(" %d packages, from the following sections:",totalcount);
+    width= 0;
+    for (se= sectionentries; se; se= se->next) {
+      sprintf(buf,"%d",se->count);
+      width -= (6 + strlen(se->name) + strlen(buf));
+      if (width < 0) { putchar('\n'); width= 73 - strlen(se->name) - strlen(buf); }
+      printf("   %s (%d)",se->name,se->count);
+    }
+    putchar('\n');
+  }
+  fflush(stdout);
+  if (ferror(stdout)) werr("stdout");
+}
+
+static int searchoutput(struct filenamenode *namenode) {
+  int found, i;
+  struct filepackages *packageslump;
+
+  found= 0;
+  for (packageslump= namenode->packages;
+       packageslump;
+       packageslump= packageslump->more) {
+    for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+      if (found) fputs(", ",stdout);
+      fputs(packageslump->pkgs[i]->name,stdout);
+      found++;
+    }
+  }
+  if (found) printf(": %s\n",namenode->name);
+  return found;
+}
+
+void searchfiles(const char *const *argv) {
+  struct filenamenode *namenode;
+  struct fileiterator *it;
+  const char *thisarg;
+  int found;
+  static struct varbuf vb;
+  
+  if (!*argv)
+    badusage("--search needs at least one file name pattern argument");
+
+  modstatdb_init(admindir,msdbrw_readonly);
+  ensure_allinstfiles_available_quiet();
+
+  while ((thisarg= *argv++) != 0) {
+    found= 0;
+    if (!strchr("*[?/",*thisarg)) {
+      varbufreset(&vb);
+      varbufaddc(&vb,'*');
+      varbufaddstr(&vb,thisarg);
+      varbufaddc(&vb,'*');
+      varbufaddc(&vb,0);
+      thisarg= vb.buf;
+    }
+    if (strcspn(thisarg,"*[?\\") == strlen(thisarg)) {
+      namenode= findnamenode(thisarg);
+      found += searchoutput(namenode);
+    } else {
+      it= iterfilestart();
+      while ((namenode= iterfilenext(it)) != 0) {
+        if (fnmatch(thisarg,namenode->name,0)) continue;
+        found+= searchoutput(namenode);
+      }
+      iterfileend(it);
+    }
+    if (!found) {
+      fprintf(stderr,DPKG ": %s not found.\n",thisarg);
+      if (ferror(stderr)) werr("stderr");
+    } else {
+      if (ferror(stdout)) werr("stdout");
+    }
+  }
+}
+
+void enqperpackage(const char *const *argv) {
+  int failures;
+  const char *thisarg;
+  struct fileinlist *file;
+  struct pkginfo *pkg;
+  
+  if (!*argv)
+    badusage("--%s needs at least one package name argument", cipaction->olong);
+
+  failures= 0;
+  modstatdb_init(admindir,msdbrw_readonly);
+  
+  while ((thisarg= *argv++) != 0) {
+    pkg= findpackage(thisarg);
+
+    switch (cipaction->arg) {
+      
+    case act_status:
+      if (pkg->status == stat_notinstalled &&
+          pkg->priority == pri_unknown &&
+          !(pkg->section && *pkg->section) &&
+          !pkg->files &&
+          pkg->want == want_unknown &&
+          !informativeperfile(&pkg->installed)) {
+        printf("Package `%s' is not installed and no info is available.\n",pkg->name);
+        failures++;
+      } else {
+        writerecord(stdout, "<stdout>", pkg, &pkg->installed);
+      }
+      break;
+
+    case act_listfiles:
+      switch (pkg->status) {
+      case stat_notinstalled: 
+        printf("Package `%s' is not installed.\n",pkg->name);
+        failures++;
+        break;
+        
+      default:
+        ensure_packagefiles_available(pkg);
+        file= pkg->clientdata->files;
+        if (!file) {
+          printf("Package `%s' does not contain any files (!)\n",pkg->name);
+        } else {
+          while (file) {
+            puts(file->namenode->name);
+            file= file->next;
+          }
+        }
+        break;
+      }
+      break;
+
+    default:
+      internerr("unknown action");
+    }
+        
+    putchar('\n');
+    if (ferror(stdout)) werr("stdout");
+  }
+
+  if (failures) {
+    puts("Use " DPKG " --info (= " BACKEND " --info) to examine archive files,\n"
+         "and " DPKG " --contents (= " BACKEND " --contents) to list their contents.");
+    if (ferror(stdout)) werr("stdout");
+  }
+}
+
+void assertsupportpredepends(const char *const *argv) {
+  struct pkginfo *pkg;
+  
+  if (*argv) badusage("--assert-support-predepends does not take any arguments");
+
+  modstatdb_init(admindir,msdbrw_readonly);
+  pkg= findpackage("dpkg");
+
+  switch (pkg->status) {
+  case stat_installed:
+    break;
+  case stat_unpacked: case stat_halfconfigured:
+    if (versionsatisfied5(pkg->configversion,pkg->configrevision,
+                          "1.1.0","", dvr_laterequal))
+      break;
+    printf("Version of dpkg with Pre-Depends support not yet configured.\n"
+           " Please use `dpkg --configure dpkg', and then try again.\n");
+    exit(1);
+  default:
+    printf("dpkg not recorded as installed, cannot check for Pre-Depends support !\n");
+    exit(1);
+  }
+}
+
+void predeppackage(const char *const *argv) {
+  /* Print a single package which:
+   *  (a) is the target of one or more relevant predependencies.
+   *  (b) has itself no unsatisfied pre-dependencies.
+   * If such a package is present output is the Packages file entry,
+   *  which can be massaged as appropriate.
+   * Exit status:
+   *  0 = a package printed, OK
+   *  1 = no suitable package available
+   *  2 = error
+   */
+  static struct varbuf vb;
+  
+  struct pkgiterator *it;
+  struct pkginfo *pkg, *startpkg, *trypkg;
+  struct dependency *dep;
+  struct deppossi *possi, *provider;
+
+  if (*argv) badusage("--predep-package does not take any argument");
+
+  modstatdb_init(admindir,msdbrw_readonly);
+  clear_istobes(); /* We use clientdata->istobe to detect loops */
+
+  for (it=iterpkgstart(), dep=0;
+       !dep && (pkg=iterpkgnext(it));
+       ) {
+    if (pkg->want != want_install) continue; /* Ignore packages user doesn't want */
+    if (!pkg->files) continue; /* Ignore packages not available */
+    pkg->clientdata->istobe= itb_preinstall;
+    for (dep= pkg->available.depends; dep; dep= dep->next) {
+      if (dep->type != dep_predepends) continue;
+      if (depisok(dep,&vb,0,1)) continue;
+      break; /* This will leave dep non-NULL, and so exit the loop. */
+    }
+    pkg->clientdata->istobe= itb_normal;
+    /* If dep is NULL we go and get the next package. */
+  }
+  if (!dep) exit(1); /* Not found */
+  assert(pkg);
+  startpkg= pkg;
+  pkg->clientdata->istobe= itb_preinstall;
+
+  /* OK, we have found an unsatisfied predependency.
+   * Now go and find the first thing we need to install, as a first step
+   * towards satisfying it.
+   */
+  do {
+    /* We search for a package which would satisfy dep, and put it in pkg */
+    for (possi=dep->list, pkg=0;
+         !pkg && possi;
+         possi=possi->next) {
+      trypkg= possi->ed;
+      if (!trypkg->available.valid) continue;
+      if (trypkg->files && versionsatisfied(&trypkg->available,possi)) {
+        if (trypkg->clientdata->istobe == itb_normal) { pkg= trypkg; break; }
+      }
+      if (possi->verrel != dvr_none) continue;
+      for (provider=possi->ed->available.depended;
+           !pkg && provider;
+           provider=provider->next) {
+        if (provider->up->type != dep_provides) continue;
+        trypkg= provider->up->up;
+        if (!trypkg->available.valid || !trypkg->files) continue;
+        if (trypkg->clientdata->istobe == itb_normal) { pkg= trypkg; break; }
+      }
+    }
+    if (!pkg) {
+      varbufreset(&vb);
+      describedepcon(&vb,dep);
+      varbufaddc(&vb,0);
+      fprintf(stderr, DPKG ": cannot see how to satisfy pre-dependency:\n %s\n",vb.buf);
+      ohshit("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)",
+             dep->up->name,startpkg->name);
+    }
+    pkg->clientdata->istobe= itb_preinstall;
+    for (dep= pkg->available.depends; dep; dep= dep->next) {
+      if (dep->type != dep_predepends) continue;
+      if (depisok(dep,&vb,0,1)) continue;
+      break; /* This will leave dep non-NULL, and so exit the loop. */
+    }
+  } while (dep);
+
+  /* OK, we've found it - pkg has no unsatisfied pre-dependencies ! */
+  writerecord(stdout,"<stdout>",pkg,&pkg->available);
+  if (fflush(stdout)) werr("stdout");
+}
+
+static void badlgccfn(const char *compiler, const char *output, const char *why)
+     NONRETURNING;
+static void badlgccfn(const char *compiler, const char *output, const char *why) {
+  fprintf(stderr,
+          DPKG ": unexpected output from `%s --print-libgcc-file-name':\n"
+          " `%s'\n",
+          compiler,output);
+  ohshit("compiler libgcc filename not understood: %.250s",why);
+}
+
+void printarchitecture(const char *const *argv) {
+  static const struct { const char *from, *to; } archtable[]= {
+#include "archtable.inc"
+    { 0,0 }
+  }, *archp;
+                  
+  const char *ccompiler, *arch;
+  int p1[2], c;
+  pid_t c1;
+  FILE *ccpipe;
+  struct varbuf vb;
+  ptrdiff_t ll;
+  char *p, *q;
+
+  ccompiler= getenv("CC");
+  if (!ccompiler) ccompiler= "gcc";
+  varbufinit(&vb);
+  m_pipe(p1);
+  ccpipe= fdopen(p1[0],"r"); if (!ccpipe) ohshite("failed to fdopen CC pipe");
+  if (!(c1= m_fork())) {
+    m_dup2(p1[1],1); close(p1[0]); close(p1[1]);
+    execlp(ccompiler,ccompiler,"--print-libgcc-file-name",(char*)0);
+    ohshite("failed to exec C compiler `%.250s'",ccompiler);
+  }
+  close(p1[1]);
+  while ((c= getc(ccpipe)) != EOF) varbufaddc(&vb,c);
+  if (ferror(ccpipe)) ohshite("error reading from CC pipe");
+  waitsubproc(c1,"gcc --print-libgcc-file-name",0);
+  if (!vb.used) badlgccfn(ccompiler,"","empty output");
+  varbufaddc(&vb,0);
+  if (vb.buf[vb.used-2] != '\n') badlgccfn(ccompiler,vb.buf,"no newline");
+  vb.used-= 2; varbufaddc(&vb,0);
+  p= strstr(vb.buf,"/gcc-lib/");
+  if (!p) badlgccfn(ccompiler,vb.buf,"no gcc-lib component");
+  p+= 9;
+  q= strchr(p,'-'); if (!q) badlgccfn(ccompiler,vb.buf,"no hyphen after gcc-lib");
+  ll= q-p;
+  for (archp=archtable;
+       archp->from && !(strlen(archp->from) == ll && !strncmp(archp->from,p,ll));
+       archp++);
+  arch= archp->to;
+  if (!arch) {
+    *q= 0; arch= p;
+    fprintf(stderr,DPKG ": warning, architecture `%s' not in remapping table\n",arch);
+  }
+  if (printf("%s\n",arch) == EOF) werr("stdout");
+  if (fflush(stdout)) werr("stdout");
+}
diff --git a/main/errors.c b/main/errors.c
new file mode 100644 (file)
index 0000000..b4064b2
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * dpkg - main program for package management
+ * main.c - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "main.h"
+
+int nerrs= 0;
+
+struct error_report {
+  struct error_report *next;
+  const char *what;
+};
+
+static struct error_report *reports=0;
+static struct error_report **lastreport= &reports;
+static struct error_report emergency;
+
+void print_error_perpackage(const char *emsg, const char *arg) {
+  struct error_report *nr;
+  
+  fprintf(stderr, DPKG ": error processing %s (--%s):\n %s\n",
+          arg, cipaction->olong, emsg);
+  nr= malloc(sizeof(struct error_report));
+  if (!nr) {
+    perror(DPKG ": failed to allocate memory for new entry in list of failed packages.");
+    onerr_abort++;
+    nr= &emergency;
+  }
+  nr->what= arg;
+  nr->next= 0;
+  *lastreport= nr;
+  lastreport= &nr->next;
+    
+  if (nerrs++ < 20) return;
+  fprintf(stderr, DPKG ": too many errors, stopping\n");
+  onerr_abort++;
+}
+
+int reportbroken_retexitstatus(void) {
+  if (reports) {
+    fputs("Errors were encountered while processing:\n",stderr);
+    while (reports) {
+      fprintf(stderr," %s\n",reports->what);
+      reports= reports->next;
+    }
+  }
+  if (onerr_abort) {
+    fputs("Processing was halted because there were too many errors.\n",stderr);
+  }
+  return nerrs || onerr_abort ? 1 : 0;
+}
+
+int skip_due_to_hold(struct pkginfo *pkg) {
+  if (!(pkg->eflag & eflagf_hold)) return 0;
+  if (fc_hold) {
+    fprintf(stderr, "Package %s was on hold, processing it anyway as you request\n",
+            pkg->name);
+    return 0;
+  }
+  printf("Package %s is on hold, not touching it.  Use --force-hold to override.\n",
+         pkg->name);
+  return 1;
+}
+
+void forcibleerr(int forceflag, const char *fmt, ...) {
+  va_list al;
+  va_start(al,fmt);
+  if (forceflag) {
+    fputs(DPKG " - warning, overriding problem because you used --force:\n ",stderr);
+    vfprintf(stderr,fmt,al);
+    fputc('\n',stderr);
+  } else {
+    ohshitv(fmt,al);
+  }
+  va_end(al);
+}
diff --git a/main/filesdb.c b/main/filesdb.c
new file mode 100644 (file)
index 0000000..642af36
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * dpkg - main program for package management
+ * filesdb.c - management of database of files installed on system
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+/*** Generic data structures and routines ***/
+
+static int allpackagesdone= 0;
+static int nfiles= 0;
+static struct diversion *diversions= 0;
+static FILE *diversionsfile= 0;
+
+void note_must_reread_files_inpackage(struct pkginfo *pkg) {
+  allpackagesdone= 0;
+  ensure_package_clientdata(pkg);
+  pkg->clientdata->fileslistvalid= 0;
+}
+
+static int saidread=0;
+
+void ensure_packagefiles_available(struct pkginfo *pkg) {
+  static struct varbuf fnvb;
+  static char stdiobuf[8192];
+  
+  FILE *file;
+  const char *filelistfile;
+  struct fileinlist **lendp, *newent, *current;
+  struct filepackages *packageslump;
+  int search, findlast, putat, l;
+  char *thefilename;
+  char linebuf[1024];
+
+  if (pkg->clientdata && pkg->clientdata->fileslistvalid) return;
+  ensure_package_clientdata(pkg);
+
+  /* Throw away any the stale data, if there was any. */
+  for (current= pkg->clientdata->files;
+       current;
+       current= current->next) {
+    /* For each file that used to be in the package,
+     * go through looking for this package's entry in the list
+     * of packages containing this file, and blank it out.
+     */
+    for (packageslump= current->namenode->packages;
+         packageslump;
+         packageslump= packageslump->more)
+      for (search= 0;
+           search < PERFILEPACKAGESLUMP && packageslump->pkgs[search];
+           search++)
+        if (packageslump->pkgs[search] == pkg) {
+          /* Hah!  Found it. */
+          for (findlast= search+1;
+               findlast < PERFILEPACKAGESLUMP && packageslump->pkgs[findlast];
+               findlast++);
+          findlast--;
+          /* findlast is now the last occupied entry, which may be the same as
+           * search.  We blank out the entry for this package.  We also
+           * have to copy the last entry into the empty slot, because
+           * the list is null-pointer-terminated.
+           */
+          packageslump->pkgs[search]= packageslump->pkgs[findlast];
+          packageslump->pkgs[findlast]= 0;
+          /* This may result in an empty link in the list.  This is OK. */
+          goto xit_search_to_delete_from_perfilenodelist;
+        }
+  xit_search_to_delete_from_perfilenodelist:
+    ;
+    /* The actual filelist links were allocated using nfmalloc, so
+     * we shouldn't free them.
+     */
+  }
+  pkg->clientdata->files= 0;
+
+  /* Packages which aren't installed don't have a files list. */
+  if (pkg->status == stat_notinstalled) {
+    pkg->clientdata->fileslistvalid= 1; return;
+  }
+
+  filelistfile= pkgadminfile(pkg,LISTFILE);
+
+  onerr_abort++;
+  
+  file= fopen(filelistfile,"r");
+
+  if (!file) {
+    if (errno != ENOENT)
+      ohshite("unable to open files list file for package `%.250s'",pkg->name);
+    onerr_abort--;
+    if (pkg->status != stat_configfiles) {
+      if (saidread == 1) putc('\n',stderr);
+      fprintf(stderr,
+              DPKG ": serious warning: files list file for package `%.250s' missing,"
+              " assuming package has no files currently installed.\n", pkg->name);
+    }
+    pkg->clientdata->files= 0;
+    pkg->clientdata->fileslistvalid= 1;
+    return;
+  }
+
+  push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
+  
+  if (setvbuf(file,stdiobuf,_IOFBF,sizeof(stdiobuf)))
+    ohshite("unable to set buffering on `%.250s'",filelistfile);
+  
+  lendp= &pkg->clientdata->files;
+  varbufreset(&fnvb);
+  while (fgets(linebuf,sizeof(linebuf),file)) {
+    /* This is a very important loop, and it is therefore rather messy.
+     * We break the varbuf abstraction even more than usual, and we
+     * avoid copying where possible.
+     */
+    l= strlen(linebuf);
+    if (l == 0) ohshit("fgets gave an empty null-terminated string from `%.250s'",
+                       filelistfile);
+    l--;
+    if (linebuf[l] != '\n') {
+      varbufaddstr(&fnvb,linebuf);
+      continue;
+    } else if (!fnvb.used && l>0 && linebuf[l-1] != '/') { /* fast path */
+      linebuf[l]= 0;
+      thefilename= linebuf;
+    } else {
+      if (l>0 && linebuf[l-1] == '/') l--; /* strip trailing slashes */
+      linebuf[l]= 0;
+      varbufaddstr(&fnvb,linebuf);
+      varbufaddc(&fnvb,0);
+      fnvb.used= 0;
+      thefilename= fnvb.buf;
+    }
+    if (!*thefilename)
+      ohshit("files list file for package `%.250s' contains empty filename",pkg->name);
+    newent= nfmalloc(sizeof(struct fileinlist));
+    newent->namenode= findnamenode(thefilename);
+    newent->next= 0;
+    *lendp= newent;
+    lendp= &newent->next;
+  }
+  if (ferror(file))
+    ohshite("error reading files list file for package `%.250s'",pkg->name);
+  pop_cleanup(ehflag_normaltidy); /* file= fopen() */
+  if (fclose(file))
+    ohshite("error closing files list file for package `%.250s'",pkg->name);
+  if (fnvb.used)
+    ohshit("files list file for package `%.250s' is truncated",pkg->name);
+
+  onerr_abort--;
+
+  for (newent= pkg->clientdata->files; newent; newent= newent->next) {
+    packageslump= newent->namenode->packages;
+    if (packageslump) {
+      for (putat= 0;
+           putat < PERFILEPACKAGESLUMP && packageslump->pkgs[putat];
+           putat++);
+      if (putat >= PERFILEPACKAGESLUMP) packageslump= 0;
+    }
+    if (!packageslump) {
+      packageslump= nfmalloc(sizeof(struct filepackages));
+      packageslump->more= newent->namenode->packages;
+      newent->namenode->packages= packageslump;
+      putat= 0;
+    }
+    packageslump->pkgs[putat]= pkg;
+    if (++putat < PERFILEPACKAGESLUMP) packageslump->pkgs[putat]= 0;
+  }      
+  pkg->clientdata->fileslistvalid= 1;
+}
+
+void ensure_allinstfiles_available(void) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+    
+  if (allpackagesdone) return;
+  if (saidread<2) {
+    saidread=1;
+    printf(f_largemem>0 ? "(Reading database ... " : "(Scanning database ... ");
+  }
+  it= iterpkgstart();
+  while ((pkg= iterpkgnext(it)) != 0) ensure_packagefiles_available(pkg);
+  iterpkgend(it);
+  allpackagesdone= 1;
+
+  if (saidread==1) {
+    printf("%d files and directories currently installed.)\n",nfiles);
+    saidread=2;
+  }
+}
+
+void ensure_allinstfiles_available_quiet(void) {
+  saidread=2;
+  ensure_allinstfiles_available();
+}
+
+void write_filelist_except(struct pkginfo *pkg, struct fileinlist *list, int leaveout) {
+  /* If leaveout is nonzero, will not write any file whose filenamenode
+   * has the fnnf_elide_other_lists flag set.
+   */
+  static struct varbuf vb, newvb;
+  FILE *file;
+
+  varbufreset(&vb);
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" INFODIR);
+  varbufaddstr(&vb,pkg->name);
+  varbufaddstr(&vb,"." LISTFILE);
+  varbufaddc(&vb,0);
+
+  varbufreset(&newvb);
+  varbufaddstr(&newvb,vb.buf);
+  varbufaddstr(&newvb,NEWDBEXT);
+  varbufaddc(&newvb,0);
+  
+  file= fopen(newvb.buf,"w+");
+  if (!file)
+    ohshite("unable to create updated files list file for package %s",pkg->name);
+  push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
+  while (list) {
+    if (!(leaveout && (list->namenode->flags & fnnf_elide_other_lists))) {
+      fputs(list->namenode->name,file);
+      putc('\n',file);
+    }
+    list= list->next;
+  }
+  if (ferror(file))
+    ohshite("failed to write to updated files list file for package %s",pkg->name);
+  if (fflush(file))
+    ohshite("failed to flush updated files list file for package %s",pkg->name);
+  if (fsync(fileno(file)))
+    ohshite("failed to sync updated files list file for package %s",pkg->name);
+  pop_cleanup(ehflag_normaltidy); /* file= fopen() */
+  if (fclose(file))
+    ohshite("failed to close updated files list file for package %s",pkg->name);
+  if (rename(newvb.buf,vb.buf))
+    ohshite("failed to install updated files list file for package %s",pkg->name);
+
+  note_must_reread_files_inpackage(pkg);
+}
+
+void reversefilelist_init(struct reversefilelistiter *iterptr,
+                          struct fileinlist *files) {
+  /* Initialises an iterator that appears to go through the file
+   * list `files' in reverse order, returning the namenode from
+   * each.  What actually happens is that we walk the list here,
+   * building up a reverse list, and then peel it apart one
+   * entry at a time.
+   */
+  struct fileinlist *newent;
+  
+  iterptr->todo= 0;
+  while (files) {
+    newent= m_malloc(sizeof(struct fileinlist));
+    newent->namenode= files->namenode;
+    newent->next= iterptr->todo;
+    iterptr->todo= newent;
+    files= files->next;
+  }
+}
+
+struct filenamenode *reversefilelist_next(struct reversefilelistiter *iterptr) {
+  struct filenamenode *ret;
+  struct fileinlist *todo;
+
+  todo= iterptr->todo;
+  if (!todo) return 0;
+  ret= todo->namenode;
+  iterptr->todo= todo->next;
+  free(todo);
+  return ret;
+}
+
+void reversefilelist_abort(struct reversefilelistiter *iterptr) {
+  /* Clients must call this function to clean up the reversefilelistiter
+   * if they wish to break out of the iteration before it is all done.
+   * Calling this function is not necessary if reversefilelist_next has
+   * been called until it returned 0.
+   */
+  while (reversefilelist_next(iterptr));
+}
+
+void ensure_diversions(void) {
+  static struct varbuf vb;
+
+  struct stat stab1, stab2;
+  char linebuf[MAXDIVERTFILENAME];
+  FILE *file;
+  struct diversion *ov, *oicontest, *oialtname;
+  int l;
+  
+  varbufreset(&vb);
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" DIVERSIONSFILE);
+  varbufaddc(&vb,0);
+
+  onerr_abort++;
+  
+  file= fopen(vb.buf,"r");
+  if (!file) {
+    if (errno != ENOENT) ohshite("failed to open diversions file");
+    if (!diversionsfile) { onerr_abort--; return; }
+  } else if (diversionsfile) {
+    if (fstat(fileno(diversionsfile),&stab1))
+      ohshite("failed to fstat previous diversions file");
+    if (fstat(fileno(file),&stab2))
+      ohshite("failed to fstat diversions file");
+    if (stab1.st_dev == stab2.st_dev && stab1.st_ino == stab2.st_ino) {
+      fclose(file); onerr_abort--; return;
+    }
+  }
+  if (diversionsfile) fclose(diversionsfile);
+  diversionsfile= file;
+
+  for (ov= diversions; ov; ov= ov->next) {
+    ov->useinstead->divert= 0;
+    ov->camefrom->divert= 0;
+  }
+  if (!file) { onerr_abort--; return; }
+
+  while (fgets(linebuf,sizeof(linebuf),file)) {
+    oicontest= nfmalloc(sizeof(struct diversion));
+    oialtname= nfmalloc(sizeof(struct diversion));
+
+    l= strlen(linebuf);
+    if (l == 0) ohshit("fgets gave an empty string from diversions [i]");
+    if (linebuf[--l] != '\n') ohshit("diversions file has too-long line or EOF [i]");
+    linebuf[l]= 0;
+    oialtname->camefrom= findnamenode(linebuf);
+    
+    if (!fgets(linebuf,sizeof(linebuf),file))
+      if (ferror(file)) ohshite("read error in diversions [ii]");
+      else ohshit("unexpected EOF in diversions [ii]");
+    l= strlen(linebuf);
+    if (l == 0) ohshit("fgets gave an empty string from diversions [ii]");
+    if (linebuf[--l] != '\n') ohshit("diversions file has too-long line or EOF [ii]");
+    linebuf[l]= 0;
+    oicontest->useinstead= findnamenode(linebuf);
+    
+    if (!fgets(linebuf,sizeof(linebuf),file))
+      if (ferror(file)) ohshite("read error in diversions [iii]");
+      else ohshit("unexpected EOF in diversions [iii]");
+    l= strlen(linebuf);
+    if (l == 0) ohshit("fgets gave an empty string from diversions [iii]");
+    if (linebuf[--l] != '\n') ohshit("diversions file has too-long line or EOF [ii]");
+    linebuf[l]= 0;
+
+    oicontest->pkg= oialtname->pkg=
+      strcmp(linebuf,":") ? findpackage(linebuf) : 0;
+
+    if (oialtname->camefrom->divert || oicontest->useinstead->divert)
+      ohshit("conflicting diversions involving `%.250s' or `%.250s'",
+             oicontest->camefrom->name, oicontest->useinstead->name);
+
+    oialtname->camefrom->divert= oicontest;
+    oicontest->useinstead->divert= oialtname;
+  }
+  if (ferror(file)) ohshite("read error in diversions [i]");
+
+  diversionsfile= file;
+  onerr_abort--;
+}
+
+/*** Data structures common to both in-core databases ***/
+
+struct fileiterator {
+  union {
+    struct {
+      struct filenamenode *current;
+    } low;
+    struct {
+      struct filenamenode *namenode;
+      int nbinn;
+    } high;
+  } u;
+};
+
+/*** Data structures for fast, large memory usage database ***/
+
+#define BINS (1 << 13)
+ /* This must always be a power of two.  If you change it
+  * consider changing the per-character hashing factor (currently
+  * 1785 = 137*13) too.
+  */
+
+static struct filenamenode *bins[BINS];
+
+/*** Data structures for low-memory-footprint in-core files database ***/
+
+struct fdirents {
+  struct fdirents *more;
+  struct { const char *component; struct fdirnode *go; } entries[1];
+  /* first one has one entry, then two, then four, &c */
+};
+
+struct fdirnode {
+  struct filenamenode *here;
+  struct fdirents *contents;
+};
+
+static struct fdirnode fdirroot;
+static struct filenamenode *allfiles;
+
+struct filenamesblock {
+  struct filenamesblock *next;
+  char *data;
+};
+
+static struct filenamesblock *namesarea= 0;
+static int namesarealeft= 0;
+
+/*** Code for both.  This is rather hacky, sorry ... ***/
+
+struct fileiterator *iterfilestart(void) {
+  struct fileiterator *i;
+  i= m_malloc(sizeof(struct fileiterator));
+  switch (f_largemem) {
+  case 1:
+    i->u.high.namenode= 0;
+    i->u.high.nbinn= 0;
+    break;
+  case -1:
+    i->u.low.current= allfiles;
+    break;
+  default:
+    internerr("iterfilestart no f_largemem");
+  }
+  return i;
+}
+
+struct filenamenode *iterfilenext(struct fileiterator *i) {
+  struct filenamenode *r;
+  switch (f_largemem) {
+  case 1:
+    while (!i->u.high.namenode) {
+      if (i->u.high.nbinn >= BINS) return 0;
+      i->u.high.namenode= bins[i->u.high.nbinn++];
+    }
+    r= i->u.high.namenode;
+    i->u.high.namenode= r->next;
+    break;
+  case -1:
+    if (!i->u.low.current) return 0;
+    r= i->u.low.current;
+    i->u.low.current= i->u.low.current->next;
+    break;
+  default:
+    internerr("iterfilenext no f_largemem");
+  }
+  return r;
+}
+
+void iterfileend(struct fileiterator *i) {
+  free(i);
+}
+
+void filesdbinit(void) {
+  struct filenamenode *fnn;
+  struct sysinfo info;
+  int i;
+
+  if (!f_largemem) {
+    f_largemem= -1;
+    if (!sysinfo(&info)) {
+      if (info.freeram + (info.sharedram>>2) + (info.bufferram>>2) >= 4096*1024 ||
+          info.totalram >= 6144)
+        f_largemem= 1;
+    }
+  }
+  
+  switch (f_largemem) {
+  case 1:
+    for (i=0; i<BINS; i++)
+      for (fnn= bins[i]; fnn; fnn= fnn->next) {
+        fnn->flags= 0;
+        fnn->oldhash= 0;
+      }
+    break;
+  case -1:
+    for (fnn= allfiles;
+         fnn;
+         fnn= fnn->next) {
+      fnn->flags= 0;
+      fnn->oldhash= 0;
+    }
+    break;
+  default:
+    internerr("filesdbinit no f_largemem");
+  }    
+}
+
+static struct filenamenode *findnamenode_high(const char *name);
+static struct filenamenode *findnamenode_low(const char *name);
+  
+struct filenamenode *findnamenode(const char *name) {
+  switch (f_largemem) {
+  case 1:
+    return findnamenode_high(name);
+  case -1:
+    return findnamenode_low(name);
+  default:
+    internerr("findnamenode no f_largemem");
+  }
+}
+
+/*** Code for low-memory-footprint in-core files database ***/
+  
+static struct filenamenode *findnamenode_low(const char *name) {
+  struct fdirnode *traverse;
+  struct fdirents *ents, **addto;
+  const char *nameleft, *slash;
+  char *p;
+  struct filenamesblock *newblock;
+  int n, i, nentrieshere, alloc;
+
+  /* We skip initial slashes and ./ pairs, and add our own single leading slash. */
+  name= skip_slash_dotslash(name);
+
+  nameleft= name;
+  traverse= &fdirroot;
+  while (nameleft) {
+    slash= strchr(nameleft,'/');
+    if (slash) {
+      n= (int)(slash-nameleft); slash++;
+    } else {
+      n= strlen(nameleft);
+    }
+    ents= traverse->contents; addto= &traverse->contents; i= 0; nentrieshere= 1;
+    for (;;) {
+      if (!ents) break;
+      if (!ents->entries[i].component) break;
+      if (!strncmp(ents->entries[i].component,nameleft,n) &&
+          !ents->entries[i].component[n]) {
+        break;
+      }
+      i++;
+      if (i < nentrieshere) continue;
+      addto= &ents->more;
+      ents= ents->more;
+      nentrieshere += nentrieshere;
+      i=0;
+    }
+    if (!ents) {
+      ents= nfmalloc(sizeof(struct fdirents) +
+                     sizeof(ents->entries[0])*(nentrieshere-1));
+      i=0;
+      ents->entries[i].component= 0;
+      ents->more= 0;
+      *addto= ents;
+    }
+    if (!ents->entries[i].component) {
+      p= nfmalloc(n+1);
+      memcpy(p,nameleft,n); p[n]= 0;
+      ents->entries[i].component= p;
+      ents->entries[i].go= nfmalloc(sizeof(struct fdirnode));
+      ents->entries[i].go->here= 0;
+      ents->entries[i].go->contents= 0;
+      if (i+1 < nentrieshere)
+        ents->entries[i+1].component= 0;
+    }
+    traverse= ents->entries[i].go;
+    nameleft= slash;
+  }
+  if (traverse->here) return traverse->here;
+
+  traverse->here= nfmalloc(sizeof(struct filenamenode));
+  traverse->here->packages= 0;
+  traverse->here->flags= 0;
+  traverse->here->divert= 0;
+
+  n= strlen(name)+2;
+  if (namesarealeft < n) {
+    newblock= m_malloc(sizeof(struct filenamesblock));
+    alloc= 256*1024;
+    if (alloc<n) alloc= n;
+    newblock->data= m_malloc(alloc);
+    newblock->next= namesarea;
+    namesarea= newblock;
+    namesarealeft= alloc;
+  }
+  namesarealeft-= n;
+  p= namesarea->data+namesarealeft;
+  traverse->here->name= p; *p++= '/'; strcpy(p,name);
+
+  traverse->here->next= allfiles;
+  allfiles= traverse->here;
+  nfiles++;
+  return traverse->here;  
+}
+
+/*** Code for high memory usage fast database ***/
+
+static int hash(const char *name) {
+  int v= 0;
+  while (*name) { v *= 1785; v += *name; name++; }
+  return v;
+}
+
+struct filenamenode *findnamenode_high(const char *name) {
+  struct filenamenode **pointerp, *newnode;
+
+  /* We skip initial slashes and ./ pairs, and add our own single leading slash. */
+  name= skip_slash_dotslash(name);
+
+  pointerp= bins + (hash(name) & (BINS-1));
+  while (*pointerp) {
+    assert((*pointerp)->name[0] == '/');
+    if (!strcmp((*pointerp)->name+1,name)) break;
+    pointerp= &(*pointerp)->next;
+  }
+  if (*pointerp) return *pointerp;
+
+  newnode= nfmalloc(sizeof(struct filenamenode));
+  newnode->packages= 0;
+  newnode->name= nfmalloc(strlen(name)+2);
+  newnode->name[0]= '/'; strcpy(newnode->name+1,name);
+  newnode->flags= 0;
+  newnode->next= 0;
+  newnode->divert= 0;
+  *pointerp= newnode;
+  nfiles++;
+
+  return newnode;
+}
diff --git a/main/filesdb.h b/main/filesdb.h
new file mode 100644 (file)
index 0000000..f650c51
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * dpkg - main program for package management
+ * filesdb.h - management of database of files installed on system
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef FILESDB_H
+#define FILESDB_H
+
+/*
+ * Data structure here is as follows:
+ * 
+ * For each package we have a `struct fileinlist *', the head of
+ * a list of files in that package.  They are in `forwards' order.
+ * Each entry has a pointer to the `struct filenamenode'.
+ *
+ * The struct filenamenodes are in a hash table, indexed by name.
+ * (This hash table is not visible to callers.)
+ *
+ * Each filenamenode has a (possibly empty) list of `struct
+ * filepackage', giving a list of the packages listing that
+ * filename.
+ *
+ * When we read files contained info about a particular package
+ * we set the `files' member of the clientdata struct to the
+ * appropriate thing.  When not yet set the files pointer is
+ * made to point to `fileslist_uninited' (this is available only
+ * internally, withing filesdb.c - the published interface is
+ * ensure_*_available).
+ */
+
+struct pkginfo;
+
+struct filenamenode {
+  struct filenamenode *next;
+  char *name;
+  struct filepackages *packages;
+  struct diversion *divert;
+  /* Fields from here on are used by archives.c &c, and cleared by
+   * filesdbinit.
+   */
+  enum {
+    fnnf_new_conff=           000001, /* in the newconffiles list */
+    fnnf_new_inarchive=       000002, /* in the new filesystem archive */
+    fnnf_old_conff=           000004, /* in the old package's conffiles list */
+    fnnf_elide_other_lists=   000010, /* must remove from other packages' lists */
+    fnnf_no_atomic_overwrite= 000020, /* >=1 instance is a dir, cannot rename over */
+  } flags; /* Set to zero when a new node is created. */
+  const char *oldhash; /* valid iff this namenode is in the newconffiles list */
+};
+struct fileinlist {
+  struct fileinlist *next;
+  struct filenamenode *namenode;
+};
+
+struct diversion {
+  /* When we deal with an `overridden' file, every package except
+   * the overriding one is considered to contain the other file
+   * instead.  Both files have entries in the filesdb database, and
+   * they refer to each other via these diversion structures.
+   *
+   * The contended filename's filenamenode has an diversion entry
+   * with useinstead set to point to the redirected filename's
+   * filenamenode; the redirected filenamenode has camefrom set to the
+   * contended filenamenode.  Both sides' diversion entries will
+   * have pkg set to the package (if any) which is allowed to use the
+   * contended filename.
+   *
+   * Packages that contain either version of the file will all
+   * refer to the contended filenamenode in their per-file package lists
+   * (both in core and on disk).  References are redirected to the other
+   * filenamenode's filename where appropriate.
+   */
+  struct filenamenode *useinstead;
+  struct filenamenode *camefrom;
+  struct pkginfo *pkg;
+  struct diversion *next;
+  /* The `contested' halves are in this list for easy cleanup. */
+};
+
+#define PERFILEPACKAGESLUMP 10
+
+struct filepackages {
+  struct filepackages *more;
+  struct pkginfo *pkgs[PERFILEPACKAGESLUMP];
+  /* pkgs is a null-pointer-terminated list; anything after the first null
+   * is garbage
+   */
+};
+
+struct fileiterator;
+struct fileiterator *iterfilestart(void);
+struct filenamenode *iterfilenext(struct fileiterator *i);
+void iterfileend(struct fileiterator *i);
+
+void ensure_diversions(void);
+
+void ensure_packagefiles_available(struct pkginfo *pkg);
+void ensure_allinstfiles_available(void);
+void ensure_allinstfiles_available_quiet(void);
+void note_must_reread_files_inpackage(struct pkginfo *pkg);
+struct filenamenode *findnamenode(const char *filename);
+void write_filelist_except(struct pkginfo *pkg, struct fileinlist *list, int leaveout);
+
+struct reversefilelistiter { struct fileinlist *todo; };
+
+void reversefilelist_init(struct reversefilelistiter *iterptr, struct fileinlist *files);
+struct filenamenode *reversefilelist_next(struct reversefilelistiter *iterptr);
+void reversefilelist_abort(struct reversefilelistiter *iterptr);
+
+#endif /* FILESDB_H */
diff --git a/main/help.c b/main/help.c
new file mode 100644 (file)
index 0000000..48378a6
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * dpkg - main program for package management
+ * help.c - various helper routines
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <dirent.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+const char *const statusstrings[]= {
+  "not installed", "unpacked but not configured",
+  "broken due to postinst failure",
+  "installed",
+  "broken due to failed removal",
+  "not installed but configs remain"
+};
+
+struct filenamenode *namenodetouse(struct filenamenode *namenode, struct pkginfo *pkg) {
+  struct filenamenode *r;
+  
+  if (!namenode->divert) return namenode;
+  
+  debug(dbg_eachfile,"namenodetouse namenode=`%s' pkg=%s",
+        namenode->name,pkg->name);
+  
+  r=
+    (namenode->divert->useinstead && namenode->divert->pkg != pkg)
+      ? namenode->divert->useinstead : namenode;
+  
+  debug(dbg_eachfile,
+        "namenodetouse ... useinstead=%s camefrom=%s pkg=%s return %s",
+        namenode->divert->useinstead ? namenode->divert->useinstead->name : "<none>",
+        namenode->divert->camefrom ? namenode->divert->camefrom->name : "<none>",
+        namenode->divert->pkg ? namenode->divert->pkg->name : "<none>",
+        r->name);
+  return r;
+}
+
+void checkpath(void) {
+  static const char *const checklist[]= {
+    "ldconfig", "start-stop-daemon", "install-info", "update-rc.d", 0
+  };
+
+  struct stat stab;
+  const char *const *clp;
+  const char *path, *s, *p;
+  char buf[PATH_MAX+2];
+  int warned= 0;
+  long l;
+
+  path= getenv("PATH");
+  if (!path) fputs(DPKG " - warning: PATH is not set.\n", stderr);
+  
+  for (clp=checklist; *clp; clp++) {
+    s= path;
+    while (s) {
+      p= strchr(s,':');
+      l= p ? p-s : strlen(s);
+      if (l+strlen(*clp)+2>sizeof(buf)) continue;
+      memcpy(buf,s,l);
+      if (l) buf[l++]= '/';
+      strcpy(buf+l,*clp);
+      if (stat(buf,&stab) == 0 && (stab.st_mode & 0111)) break;
+      s= p; if (s) s++;
+    }
+    if (!s) {
+      fprintf(stderr,DPKG ": `%s' not found on PATH.\n",*clp);
+      warned++;
+    }
+  }
+
+  if (warned)
+    forcibleerr(fc_badpath,"%d expected program(s) not found on PATH.\nNB: root's "
+                "PATH should usually contain /usr/local/sbin, /usr/sbin and /sbin.",
+                warned);
+}
+
+void ensure_package_clientdata(struct pkginfo *pkg) {
+  if (pkg->clientdata) return;
+  pkg->clientdata= nfmalloc(sizeof(struct pkginfoperfile));
+  pkg->clientdata->istobe= itb_normal;
+  pkg->clientdata->fileslistvalid= 0;
+  pkg->clientdata->files= 0;
+}
+
+void cu_closepipe(int argc, void **argv) {
+  int *p1= (int*)argv[0];
+  close(p1[0]); close(p1[1]);
+}
+
+void cu_closefile(int argc, void **argv) {
+  FILE *f= (FILE*)(argv[0]);
+  fclose(f);
+}
+
+void cu_closedir(int argc, void **argv) {
+  DIR *d= (DIR*)(argv[0]);
+  closedir(d);
+}
+
+void cu_closefd(int argc, void **argv) {
+  int *ip= (int*)(argv[0]);
+  close(*ip);
+}
+
+int ignore_depends(struct pkginfo *pkg) {
+  struct packageinlist *id;
+  for (id= ignoredependss; id; id= id->next)
+    if (id->pkg == pkg) return 1;
+  return 0;
+}
+
+int force_depends(struct deppossi *possi) {
+  return fc_depends ||
+         ignore_depends(possi->ed) ||
+         ignore_depends(possi->up->up);
+}
+
+int force_conflicts(struct deppossi *possi) {
+  return fc_conflicts;
+}
+
+const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile) {
+  static struct varbuf vb;
+  varbufreset(&vb);
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" INFODIR);
+  varbufaddstr(&vb,pkg->name);
+  varbufaddc(&vb,'.');
+  varbufaddstr(&vb,whichfile);
+  varbufaddc(&vb,0);
+  return vb.buf;
+}
+
+static void preexecscript(const char *path, char *const *argv) {
+  if (*instdir) {
+    /* fixme: won't work right when instdir != admindir */
+    if (chroot(instdir)) ohshite("failed to chroot to `%.250s'",instdir);
+  }
+  if (f_debug & dbg_scripts) {
+    fprintf(stderr,"D0%05o: fork/exec %s (",dbg_scripts,path);
+    while (*argv) fprintf(stderr," %s",*argv++);
+    fputs(" )\n",stderr);
+  }
+}  
+
+static char *const *vbuildarglist(const char *scriptname, va_list ap) {
+  static char *bufs[PKGSCRIPTMAXARGS+1];
+  char *nextarg;
+  int i;
+
+  i=0;
+  bufs[i++]= (char*)scriptname; /* yes, cast away cost because exec wants it that way */
+  for (;;) {
+    assert(i < PKGSCRIPTMAXARGS);
+    nextarg= va_arg(ap,char*);
+    if (!nextarg) break;
+    bufs[i++]= nextarg;
+  }
+  bufs[i]= 0;
+  return bufs;
+}    
+
+static char *const *buildarglist(const char *scriptname, ...) {
+  char *const *arglist;
+  va_list ap;
+  va_start(ap,scriptname);
+  arglist= vbuildarglist(scriptname,ap);
+  va_end(ap);
+  return arglist;
+}
+
+#define NSCRIPTCATCHSIGNALS sizeof(script_catchsignallist)/sizeof(int)-1
+static int script_catchsignallist[]= { SIGQUIT, SIGINT, 0 };
+static struct sigaction script_uncatchsignal[NSCRIPTCATCHSIGNALS];
+
+static void cu_restorescriptsignals(int argc, void **argv) {
+  int i;
+  for (i=0; i<NSCRIPTCATCHSIGNALS; i++) {
+    if (sigaction(script_catchsignallist[i],&script_uncatchsignal[i],0)) {
+      fprintf(stderr,"error un-catching signal %s: %s\n",
+              strsignal(script_catchsignallist[i]),strerror(errno));
+      onerr_abort++;
+    }
+  }
+}
+
+static void script_catchsignals(void) {
+  int i;
+  struct sigaction catchsig;
+  
+  onerr_abort++;
+  memset(&catchsig,0,sizeof(catchsig));
+  catchsig.sa_handler= SIG_IGN;
+  sigemptyset(&catchsig.sa_mask);
+  catchsig.sa_flags= 0;
+  for (i=0; i<NSCRIPTCATCHSIGNALS; i++)
+    if (sigaction(script_catchsignallist[i],&catchsig,&script_uncatchsignal[i]))
+      ohshite("unable to ignore signal %s before running script",
+              strsignal(script_catchsignallist[i]));
+  push_cleanup(cu_restorescriptsignals,~0, 0,0, 0);
+  onerr_abort--;
+}
+
+static void setexecute(const char *path, struct stat *stab) {
+  if ((stab->st_mode & 0555) == 0555) return;
+  if (!chmod(path,0755)) return;
+  ohshite("unable to set execute permissions on `%.250s'",path);
+}
+
+int maintainer_script_installed(struct pkginfo *pkg, const char *scriptname,
+                                const char *description, ...) {
+  /* all ...'s are const char*'s */
+  const char *scriptpath;
+  char *const *arglist;
+  struct stat stab;
+  va_list ap;
+  int c1;
+  char buf[100];
+
+  scriptpath= pkgadminfile(pkg,scriptname);
+  va_start(ap,description);
+  arglist= vbuildarglist(scriptname,ap);
+  va_end(ap);
+  sprintf(buf,"%s script",description);
+
+  if (stat(scriptpath,&stab)) {
+    if (errno == ENOENT) {
+      debug(dbg_scripts,"maintainer_script_installed nonexistent %s",scriptname);
+      return 0;
+    }
+    ohshite("unable to stat installed %s script `%.250s'",description,scriptpath);
+  }
+  setexecute(scriptpath,&stab);
+  c1= m_fork();
+  if (!c1) {
+    preexecscript(scriptpath,arglist);
+    execv(scriptpath,arglist);
+    ohshite("unable to execute %s",buf);
+  }
+  script_catchsignals(); /* This does a push_cleanup() */
+  waitsubproc(c1,buf,0);
+  pop_cleanup(ehflag_normaltidy);
+
+  ensure_diversions();
+  return 1;
+}
+  
+int maintainer_script_new(const char *scriptname, const char *description,
+                          const char *cidir, char *cidirrest, ...) {
+  char *const *arglist;
+  struct stat stab;
+  va_list ap;
+  char buf[100];
+  int c1;
+  
+  va_start(ap,cidirrest);
+  arglist= vbuildarglist(scriptname,ap);
+  va_end(ap);
+  sprintf(buf,"%s script",description);
+
+  strcpy(cidirrest,scriptname);
+  if (stat(cidir,&stab)) {
+    if (errno == ENOENT) {
+      debug(dbg_scripts,"maintainer_script_new nonexistent %s `%s'",scriptname,cidir);
+      return 0;
+    }
+    ohshite("unable to stat new %s script `%.250s'",description,cidir);
+  }
+  setexecute(cidir,&stab);
+  c1= m_fork();
+  if (!c1) {
+    preexecscript(cidir,arglist);
+    execv(cidir,arglist);
+    ohshite("unable to execute new %s",buf);
+  }
+  script_catchsignals(); /* This does a push_cleanup() */
+  waitsubproc(c1,buf,0);
+  pop_cleanup(ehflag_normaltidy);
+
+  ensure_diversions();
+  return 1;
+}
+
+int maintainer_script_alternative(struct pkginfo *pkg,
+                                  const char *scriptname, const char *description,
+                                  const char *cidir, char *cidirrest,
+                                  const char *ifok, const char *iffallback) {
+  const char *oldscriptpath;
+  char *const *arglist;
+  struct stat stab;
+  int c1, n, status;
+  char buf[100];
+  pid_t r;
+
+  oldscriptpath= pkgadminfile(pkg,scriptname);
+  arglist= buildarglist(scriptname,
+                        ifok,versiondescribe(pkg->available.version,
+                                             pkg->available.revision),
+                        (char*)0);
+  sprintf(buf,"old %s script",description);
+  if (stat(oldscriptpath,&stab)) {
+    if (errno == ENOENT) {
+      debug(dbg_scripts,"maintainer_script_alternative nonexistent %s `%s'",
+            scriptname,oldscriptpath);
+      return 0;
+    }
+    fprintf(stderr,
+            DPKG ": warning - unable to stat %s `%.250s': %s\n",
+            buf,oldscriptpath,strerror(errno));
+  } else {
+    setexecute(oldscriptpath,&stab);
+    c1= m_fork();
+    if (!c1) {
+      preexecscript(oldscriptpath,arglist);
+      execv(oldscriptpath,arglist);
+      ohshite("unable to execute %s",buf);
+    }
+    script_catchsignals(); /* This does a push_cleanup() */
+    while ((r= waitpid(c1,&status,0)) == -1 && errno == EINTR);
+    if (r != c1) ohshite("wait for %s failed",buf);
+    pop_cleanup(ehflag_normaltidy);
+    if (WIFEXITED(status)) {
+      n= WEXITSTATUS(status); if (!n) return 1;
+      fprintf(stderr, DPKG ": warning - %s returned error exit status %d\n",buf,n);
+    } else if (WIFSIGNALED(status)) {
+      n= WTERMSIG(status);
+      fprintf(stderr, DPKG ": warning - %s killed by signal (%s)%s\n",
+              buf, strsignal(n), WCOREDUMP(status) ? ", core dumped" : "");
+    } else {
+      ohshit("%s failed with unknown wait status code %d",buf,status);
+    }
+    ensure_diversions();
+  }
+  fprintf(stderr, DPKG " - trying script from the new package instead ...\n");
+
+  arglist= buildarglist(scriptname,
+                        iffallback,versiondescribe(pkg->installed.version,
+                                                   pkg->installed.revision),
+                        (char*)0);
+  strcpy(cidirrest,scriptname);
+  sprintf(buf,"new %s script",description);
+
+  if (stat(cidir,&stab))
+    if (errno == ENOENT)
+      ohshit("there is no script in the new version of the package - giving up");
+    else
+      ohshite("unable to stat %s `%.250s'",buf,cidir);
+
+  setexecute(cidir,&stab);
+
+  c1= m_fork();
+  if (!c1) {
+    preexecscript(cidir,arglist);
+    execv(cidir,arglist);
+    ohshite("unable to execute %s",buf);
+  }
+  script_catchsignals(); /* This does a push_cleanup() */
+  waitsubproc(c1,buf,0);
+  pop_cleanup(ehflag_normaltidy);
+  fprintf(stderr, DPKG ": ... it looks like that went OK.\n");
+
+  ensure_diversions();
+  return 1;
+}
+
+void clear_istobes(void) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+
+  it= iterpkgstart();
+  while ((pkg= iterpkgnext(it)) != 0) {
+    ensure_package_clientdata(pkg);
+    pkg->clientdata->istobe= itb_normal;
+    pkg->clientdata->replacingfilesandsaid= 0;
+  }
+}
+
+void debug(int which, const char *fmt, ...) {
+  va_list ap;
+  if (!(f_debug & which)) return;
+  fprintf(stderr,"D0%05o: ",which);
+  va_start(ap,fmt);
+  vfprintf(stderr,fmt,ap);
+  va_end(ap);
+  putc('\n',stderr);
+}
+
+int isdirectoryinuse(struct filenamenode *file, struct pkginfo *pkg) {
+  /* Returns 1 if the file is used by packages other than pkg, 0 otherwise. */
+  struct filepackages *packageslump;
+  int i;
+    
+  debug(dbg_veryverbose, "isdirectoryinuse `%s' (except %s)", file->name,
+        pkg ? pkg->name : "<none>");
+  for (packageslump= file->packages; packageslump; packageslump= packageslump->more) {
+    debug(dbg_veryverbose, "isdirectoryinuse packageslump %s ...",
+          packageslump->pkgs[0] ? packageslump->pkgs[0]->name : "<none>");
+    for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+      debug(dbg_veryverbose, "isdirectoryinuse considering [%d] %s ...", i,
+            packageslump->pkgs[i]->name);
+      if (packageslump->pkgs[i] == pkg) continue;
+      return 1;
+    }
+  }
+  debug(dbg_veryverbose, "isdirectoryinuse no");
+  return 0;
+}
+
+void oldconffsetflags(struct conffile *searchconff) {
+  struct filenamenode *namenode;
+  
+  while (searchconff) {
+    namenode= findnamenode(searchconff->name);
+    namenode->flags |= fnnf_old_conff;
+    debug(dbg_conffdetail, "oldconffsetflags `%s' namenode %p flags %o",
+          searchconff->name, namenode, namenode->flags);
+    searchconff= searchconff->next;
+  }
+}
+
+void ensure_pathname_nonexisting(const char *pathname) {
+  int c1;
+  const char *u;
+
+  u= skip_slash_dotslash(pathname);
+  assert(*u);
+
+  debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",pathname);
+  if (!rmdir(pathname)) return; /* Deleted it OK, it was a directory. */
+  if (errno == ENOENT || errno == ELOOP) return;
+  if (errno == ENOTDIR) {
+    /* Either it's a file, or one of the path components is.  If one
+     * of the path components is this will fail again ...
+     */
+    if (!unlink(pathname)) return; /* OK, it was */
+    if (errno == ENOTDIR) return;
+  }
+  if (errno != ENOTEMPTY) /* Huh ? */
+    ohshite("failed to rmdir/unlink `%.255s'",pathname);
+  c1= m_fork();
+  if (!c1) {
+    execlp(RM,"rm","-rf","--",pathname,(char*)0);
+    ohshite("failed to exec " RM " for cleanup");
+  }
+  debug(dbg_eachfile,"ensure_pathname_nonexisting running rm -rf");
+  waitsubproc(c1,"rm cleanup",0);
+}
diff --git a/main/junk b/main/junk
new file mode 100644 (file)
index 0000000..d5f060d
--- /dev/null
+++ b/main/junk
@@ -0,0 +1,398 @@
+if (!strcmp(newpig.name,"dpkg"))
+fprintf(stderr,"flags %o recordavailable %o config %s|%s ver %s|%s stat %d\n",
+        flags,pdb_recordavailable,newpig.configversion,newpig.configrevision,
+        newpifp->version,newpifp->revision,newpig.status);
+
+
+  if (pkg->want != want_install && f_alsoselect) {
+    printf("Selecting previously deselected package %s.\n",pkg->name);
+    pkg->want= want_install;
+  } else if (pkg->want == want_unknown && pkg->priority <= pri_standard &&
+             fc_autoselect) {
+    printf("Package %s is %s, selecting it by default.\n",pkg->name,
+           priorityinfos[pkg->priority].name);
+    pkg->want= want_install;
+  } else if (pkg->want != want_install) {
+    printf("Skipping deselected package %s.\n",pkg->name);
+    pop_cleanup(ehflag_normaltidy);
+    return;
+  }
+  
+
+
+int terminate_catchsignallist[]= { SIGINT, SIGTERM, 0 };
+int noterminal_catchsignallist[]= { SIGHUP, SIGPIPE, 0 };
+
+volatile int quitting= 0;
+
+static void terminate_sighandler(void) {
+  
+
+void terminate_catchsignals(void) {
+  int i;
+  struct sigaction catchsig;
+  
+  catchsig.sa_handler= terminate_signalhandler;
+  sigemptyset(&catchsig.sa_mask);
+  for (i=0; terminate_catchsignallist[i]; i++)
+    sigaddset(&catchsig.sa_mask,terminate_catchsignallist[i]);
+  for (i=0; noterminal_catchsignallist[i]; i++)
+    sigaddset(&catchsig.sa_mask,noterminal_catchsignallist[i]);
+  catchsig.sa_flags= 0;
+  
+  for (i=0; terminate_catchsignallist[i]; i++)
+    if (sigaction(terminate_catchsignallist[i],&catchsig,0))
+      ohshite("unable to set up signal handler for %s",
+              strsignal(terminate_catchsignallist[i]));
+  
+  catchsig.sa_handler= noterminal_signalhandler;
+  
+  for (i=0; noterminal_catchsignallist[i]; i++)
+    if (sigaction(noterminal_catchsignallist[i],&catchsig,0))
+      ohshite("unable to set up signal handler for %s",
+              strsignal(noterminal_catchsignallist[i]));
+}
+
+
+
+#!/bin/sh -
+
+set -e
+
+cd /var/lib/dpkg
+
+# This won't check for unpacked packages if we're upgrading
+# from a *really* old dpkg, but they probably didn't do
+# conffiles right anyway.
+perl -000 -ne 'print $1 if m/^Package:\s+(\S+\n)/im &&
+                          $1 ne "dpkg\n" &&
+                          m/^Status:.*unpacked/im' \
+       /var/lib/dpkg/status >/tmp/bp.$$
+if test -s /tmp/bp.$$
+then
+       echo '
+WARNING -- SOME PACKAGES IN "UNPACKED" STATE
+
+Due to a change in the filenames used for installed vs. newly-distributed
+configuration files it is NOT SAFE to upgrade to this version of dpkg
+from 
+
+
+    undef %hash; @configfr= @configf= ();
+    for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
+        s/^ //; next unless length($_);
+        if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
+            &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
+            next;
+        }
+        unshift(@configfr,$1); push(@configf,$1);
+        $hash{$1}= $2;
+    }
+    
+
+
+        undef %oldhash; @configf=();
+        for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
+            s/^ //; next unless length($_);
+            if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
+                &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
+                next;
+            }
+            $oldhash{$1}= $2; push(@configf,$1);
+            &debug("old hash of $1 is $2");
+        }
+        undef %newhash;
+
+
+
+  fextract= fdopen(p1[0],"r");
+
+  varbufinit(&thisname);
+  while ((c= fgetc(fextract)) != EOF) {
+    if (c != '\n') {
+      varbufaddc(&thisdirname,c);
+      continue;
+    }
+    varbufaddc(&thisdirname,0);
+    /* Right, this next part gets done for each file (or directory) in the
+     * archive of the new version of the package:
+     */
+    thisfile= filedatarecord(&filedata,thisname.buf);
+    thisfile->nstat= ifdnew_inarchive;
+    varbufreset(&thisname);
+  }
+  if (ferror(fextract)) ohshite("failed read from " BACKEND " extract pipe");
+  if (thisname.used) ohshit("partial filename in output from " BACKEND " extract");
+  if (fclose(fextract)) ohshite("failed to close" BACKEND " extract pipe");
+  waitsubproc(c1,BACKEND " extract archive",0);
+  
+  /* Save new file list, new conffiles &c */
+           
+    if (chdir(instdir)) ohshite("unable to change to installation root directory"
+                                " for archive extract `%.250s'",instdir);
+    execlp(BACKEND, BACKEND,"--control",filename,cidir,(char*)0);
+    ohshite("failed to exec " BACKEND " to extract control information");
+
+  /*** continue here ***/
+  
+void remove_with_backup(pkginfo *pkg, struct installingfiledata **ifdlisthead) {
+  if (f_noact) {
+    printf("(would back up files in `%s', renaming each * to *" DPKGTEMPEXT ")\n",
+           pkg->name);
+    return;
+  }
+  filesinpackagerev(pkg, &filelist);
+  for (barefile= filelist; barefile; barefile= barefile->next) {
+    thisfile= filedatarecord(ifdlisthead,barefile->name);
+    initostat(thisfile);
+    if (thisfile->ncoff) continue;
+    
+    switch (thisfile->ostat) {
+    case ifdold_directory:
+      push_cleanup(, co_olddirectory, ...);
+      break;
+      
+    case ifdold_none:
+      break;
+
+    case ifdold_file:
+      l= strlen(barefile->name);
+      toremove= m_malloc(instdirlen + l + 1);
+      strcpy(toremove,instdir); strcpy(toremove+instdirlen,barefile->name);
+      tempname= m_malloc(instdirlen + l + sizeof(DPKGTEMPEXT) + 1);
+      strcpy(tempname,toremove); strcpy(tempname+instdirlen+l,DPKGTEMPEXT);
+      ename= toremove + instdirlen;
+      tename= tempname + instdirlen;
+    
+      if (rename(toremove.buf, tempname.buf))
+        ohshite("unable to back up file-to-be-removed `%.250s'", tename);
+      push_cleanup(cu_backupfile, co_backupfile,
+                   ..., toremove,tempname);
+      break;
+      
+    default:
+      abort();
+    }
+  }
+}
+
+    case ifdold_directory:
+      for (inwhich= findfile(toremove); inwhich; inwhich= inwhich->more)
+        for (pkgsp= inwhich->pkgs; *pkgsp; pkgsp++)
+          switch ((*pkgsp)->clientdata->istobe) {
+          case itb_normal:
+            goto exit_both_loops_and_the_switch_at_once;
+          case itb_remove:
+          case itb_installnew:
+            /* We're removing or replacing this package, so that doesn't count.
+             * For packages that we replace the caller will remove the directories
+             * in the new version from the list of those to delete.
+             */
+            break;
+          default:
+            abort();
+          }
+    exit_both_loops_and_the_switch_at_once:
+
+      if (!inwhich) { /* Find it anywhere else ? */
+        struct fileinlist newdir;
+        newdir= m_malloc(sizeof(struct fileinlist));
+        newdir->name= m_malloc(strlen(ename));
+        strcpy((*addirs)->name,ename);
+        newdir->next= 0;
+        *adddirs= newdir;
+        adddirs= &newdir->next;
+      }
+      free(tempname); free(toremove);
+      continue;
+    }
+
+
+
+  l= strlen(pkg->name);
+  infdir= m_malloc(admindirlen + sizeof(INFODIR) + l + 50);
+  strcpy(infdir,admindir);
+  strcpy(infdir+admindirlen,"/" INFODIR);
+  strcpy(infdir+admindirlen+sizeof(INFODIR), pkg->name);
+  infdir[admindirlen+sizeof(INFODIR)+l-1]= '.';
+  infdirrest= infdir + admindirlen+sizeof(INFODIR)+l;
+  strcpy(infdirrest, LISTFILE);
+  strcpy(infdirrest+sizeof(LISTFILE)-1,".new");
+
+      for (thisfile= filelist; thisfile; thisfile= thisfile->next) {
+        for (thisconff= conflictor->installed.conffiles;
+             thisconff && strcmp(thisconff->name,thisfile->name);
+             thisconff= thisconff->next);
+        if (thisconff) continue;
+        varbufreset(&toremove);
+        varbufaddstr(&toremove, instdir);
+        varbufaddstr(&toremove, "/");
+        ename= toremove.buf + toremove.used;
+        varbufaddstr(&toremove, thisfile->name);
+        varbufaddc(&toremove, 0);
+        if (unlink(toremove.buf)) {
+          if (errno == EISDIR) {
+            if (rmdir(toremove.buf) && errno != ENOTEMPTY)
+              ohshite("%.250s: cannot remove directory `%.250s'",
+                      conflictor->name, ename);
+          } else if (errno != ENOENT) {
+            ohshite("%.250s: cannot remove `%.250s'", conflictor->name, ename);
+          }
+        }
+        varbufaddstr(&toremove, DPKGTEMPEXT);
+        varbufaddc(&toremove, 0);
+        if (unlink(toremove.buf) && errno != ENOENT)
+          ohshite("%.250s: cannot remove old backup file `%.250s'",
+                  conflictor->name, ename);
+      }
+                     
+        if (versionsatisfied(possi, &possi->ed.installed, &whynot)) present=1;
+  *const relatestrings[]= { "may be more useful with", "recommends",
+                            "requires", "conflicts with", "provides"                 },
+
+
+  if (possi
+
+  
+      varbufaddstr(&why, dep->up->name);
+      return 1;
+    }
+  }
+    varbufaddstr(&why, dep->up->name);
+    return 1;
+  }
+  
+      ||
+        dep->up
+    questionstatus=
+      questionstatus= dep->up->clientdata->istobe == 
+  if (up->
+      
+,
+                          if (questionstatus->status == stat_notinstalled ||
+      questionstatus->status == stat_configfiles) return 0;
+  switch (dep->type) {
+  case dep_conflicts:  reln= " conflicts with ";  break;
+  case dep_depends:    reln= " depends on ";      break;
+  default: return 1;
+  }
+  
+  varbufaddstr(whynot, dep->up->name);
+  varbufaddstr(whynot, reln);
+  reln= " ";
+
+  for (possi= dep->list; possi; possi= possi->next) {
+    varbufaddstr(whynot, reln);
+    varbufaddstr(whynot, possi->ed->name);
+    switch (possi->verrel) {
+    case dvr_none:     reln= 0;      break;
+    case dvr_later:    reln= " (>";  break;
+    case dvr_earlier:  reln= " (<";  break;
+    case dvr_exact:    reln= " (=";  break;
+    default: abort();
+    }
+    if (reln) {
+      varbufaddstr(whynot, reln);
+      varbufaddstr(whynot, possi->version);
+      if (possi->revision && *possi->revision) {
+        varbufaddc(whynot,'-');
+        varbufaddstr(whynot,possi->revision);
+      }
+      varbufaddc(whynot,')');
+    }
+    reln= " or ";
+  }    }
+        }
+        
+        if (!*linebuf) {
+          /* If the package wasn't installed at all, and we haven't said
+           * yet why this isn't satisfied, we should say so now.
+           */
+          sprintf(linebuf, "  %.250s is not installed.\n", possi->ed->name);
+          varbufaddstr(whynot, linebuf);
+        }
+      }
+    }
+    /* OK so far - now check for Providers. */
+    
+          /* Don't say anything about this yet - it might be a virtual package.
+           * Later on, if nothing has put anything in linebuf, we know that it
+           * isn't and issue a diagnostic then.
+           */
+          *linebuf= 0;
+          break;
+        default:
+          sprintf(linebuf, "  %.250s is %s.\n",
+                  possi->ed->name, );
+          break;
+        }
+        break;
+      default:
+        abort();
+      }
+  
+      
+          
+          if (possi->ed->clientdata->istobe == itb_install) continue;
+        default:
+          break;
+          
+           
+             /* fixme: what about things provided by the package(s)
+              * which we are about to install ?  For these we
+              * have to use ->available.depended.
+              */
+          varbufaddc(whynot, ' ');
+          varbufaddstr(whynot, provider->up->up->name);
+          varbufaddstr(whynot, " provides ");
+          varbufaddstr(whynot, possi->ed->name);
+      }  
+    }
+      
+          sprintf(linebuf, "  No package %.250s
+                  
+                provider->up->up->status == stat_configfiles) {
+              varbufaddstr(whynot, " but is not present.\n");
+            } else {
+              varbufaddstr(whynot, " and is present.\n");
+              present=1;
+            }
+            break;
+          case itb_install:
+            varbufaddstr(whynot, " and is to be installed.\n");
+            present=1;
+            break;
+        var
+        
+      varbufaddc(whynot, ' ');
+        
+        varbufaddstr(whynot, possi->ed->name);
+        varbufaddstr(whynot, " is to be removed.\n");
+        break;
+      case itb_normal:
+        varbufaddstr(whynot, possi->ed->name);
+        varbufaddstr(whynot, " is ");
+        if (dep->up->status == stat_installed) {
+          if (versionsatisfied(possi, &possi->ed.installed, whynot)) return 1;
+          varbufaddstr(&why, " version");
+          
+          varbufaddstr(&why, "
+          varbufaddstr(&why, " is not present.\n");
+        } else {
+        varbufaddstr(whynot, statusstrings[dep->ed->status]);
+          varbufaddstr(whynot, possi->ed->name);
+          varbufaddstr(whynot, " is present");
+        }
+        break;
+      case itb_installnew:
+        varbufaddstr(whynot, possi->ed->name);
+        varbufaddstr(whynot, " is to be installed");
+        if (versionsatisfied(possi, &possi->ed.available, whynot)) present=1;
+      default:
+        abort();
+      }
+  }
+  if (dep->type == dep_conflicts ? present : !present) return 0;
+  varbufreset(whynot); return 1;
+}
diff --git a/main/main.c b/main/main.c
new file mode 100644 (file)
index 0000000..5655410
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * dpkg - main program for package management
+ * main.c - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "version.h"
+#include "myopt.h"
+
+#include "main.h"
+
+static void printversion(void) {
+  if (!fputs("Debian GNU/Linux `" DPKG "' package management program version "
+              DPKG_VERSION_ARCH ".\n"
+             "Copyright 1994,1995 Ian Jackson, Bruce Perens.  This is free software;\n"
+             "see the GNU General Public Licence version 2 or later for copying\n"
+             "conditions.  There is NO warranty.  See dpkg --licence for details.\n",
+             stderr)) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs("\
+Usage: " DPKG " -i|--install    <.deb file name> ... | -R|--recursive <dir> ...\n\
+       " DPKG " --unpack        <.deb file name> ... | -R|--recursive <dir> ...\n\
+       " DPKG " -A|--avail      <.deb file name> ... | -R|--recursive <dir> ...\n\
+       " DPKG " --configure     <package name> ... | -a|--pending\n\
+       " DPKG " -r|--remove | --purge <package name> ... | -a|--pending\n\
+       " DPKG " -s|--status       <package-name> ...\n\
+       " DPKG " -L|--listfiles    <package-name> ...\n\
+       " DPKG " -l|--list         [<package-name-pattern> ...]\n\
+       " DPKG " -S|--search       <filename-search-pattern> ...\n\
+       " DPKG " -C|--audit | --yet-to-unpack\n\
+       " DPKG " --merge-avail | --update-avail <Packages-file>\n\
+Use " DPKG " -b|--build|-c|--contents|-e|--control|-I|--info|-f|--field|\n\
+ -x|--extract|-X|--vextract|--fsys-tarfile  on archives (type " BACKEND " --help.)\n\
+For internal use: " DPKG " --assert-support-predepends | --predep-package\n\
+\n\
+Options: --help --version --licence   --force-help  -Dh|--debug=help\n\
+         --root=<directory>   --admindir=<directory>   --instdir=<directory>\n\
+         -O|--selected-only   -E|--skip-same-version   -G=--refuse-downgrade\n\
+         -B|--auto-deconfigure   --ignore-depends=<package>,...\n\
+         -D|--debug=<octal>   --force-...  --no-force-...|--refuse-...\n\
+         --largemem|--smallmem   --no-act\n\
+\n\
+Use `" DSELECT "' for user-friendly package management.\n",
+             stderr)) werr("stderr");
+}
+
+const char thisname[]= DPKG;
+const char architecture[]= ARCHITECTURE;
+const char printforhelp[]=
+ "Type " DPKG " --help for help about installing and deinstalling packages;\n"
+ "Use " DSELECT " for user-friendly package management;\n"
+ "Type " DPKG " -Dhelp for a list of " DPKG " debug flag values;\n"
+ "Type " DPKG " --force-help for a list of forcing options;\n"
+ "Type " BACKEND " --help for help about manipulating *.deb files.";
+
+const struct cmdinfo *cipaction= 0;
+int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
+int f_autodeconf=0, f_largemem=0;
+unsigned long f_debug=0;
+int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, fc_overwrite= 0;
+int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0;
+int fc_autoselect=1, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0;
+
+const char *admindir= ADMINDIR;
+const char *instdir= "";
+struct packageinlist *ignoredependss=0;
+
+static const struct forceinfo {
+  const char *name;
+  int *opt;
+} forceinfos[]= {
+  { "downgrade",           &fc_downgrade                },
+  { "configure-any",       &fc_configureany             },
+  { "hold",                &fc_hold                     },
+  { "remove-reinstreq",    &fc_removereinstreq          },
+  { "remove-essential",    &fc_removeessential          },
+  { "conflicts",           &fc_conflicts                },
+  { "depends",             &fc_depends                  },
+  { "depends-version",     &fc_dependsversion           },
+  { "auto-select",         &fc_autoselect               },
+  { "bad-path",            &fc_badpath                  },
+  { "overwrite",           &fc_overwrite                },
+  { "overwrite-diverted",  &fc_overwritediverted        },
+  { "architecture",        &fc_architecture             },
+  {  0                                                  }
+};
+
+static void helponly(const struct cmdinfo *cip, const char *value) {
+  usage(); exit(0);
+}
+static void versiononly(const struct cmdinfo *cip, const char *value) {
+  printversion(); exit(0);
+}
+
+static void setaction(const struct cmdinfo *cip, const char *value) {
+  if (cipaction)
+    badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong);
+  cipaction= cip;
+}
+
+static void setdebug(const struct cmdinfo *cpi, const char *value) {
+  char *endp;
+
+  if (*value == 'h') {
+    if (!fputs(
+DPKG " debugging option, --debug=<octal> or -D<octal>:\n\n\
+ number  ref. in source   description\n\
+      1   general           Generally helpful progress information\n\
+      2   scripts           Invocation and status of maintainer scripts\n\
+     10   eachfile          Output for each file processed\n\
+    100   eachfiledetail    Lots of output for each file processed\n\
+     20   conff             Output for each configuration file\n\
+    200   conffdetail       Lots of output for each configuration file\n\
+     40   depcon            Dependencies and conflicts\n\
+    400   depcondetail      Lots of dependencies/conflicts output\n\
+   1000   veryverbose       Lots of drivel about eg the dpkg/info directory\n\
+   2000   stupidlyverbose   Insane amounts of drivel\n\n\
+Debugging options are be mixed using bitwise-or.\n\
+Note that the meanings and values are subject to change.\n",
+             stderr)) werr("stderr");
+    exit(0);
+  }
+  
+  f_debug= strtoul(value,&endp,8);
+  if (*endp) badusage("--debug requires an octal argument");
+}
+
+static void setroot(const struct cmdinfo *cip, const char *value) {
+  char *p;
+  instdir= value;
+  p= m_malloc(strlen(value) + sizeof(ADMINDIR));
+  strcpy(p,value);
+  strcat(p,ADMINDIR);
+  admindir= p;
+}
+
+static void ignoredepends(const struct cmdinfo *cip, const char *value) {
+  char *copy, *p;
+  const char *pnerr;
+  struct packageinlist *ni;
+
+  copy= m_malloc(strlen(value)+2);
+  strcpy(copy,value);
+  copy[strlen(value)+1]= 0;
+  for (p=copy; *p; p++) {
+    if (*p != ',') continue;
+    *p++= 0;
+    if (!*p || *p==',' || p==copy+1)
+      badusage("null package name in --ignore-depends comma-separated list `%.250s'",
+               value);
+  }
+  p= copy;
+  while (*p) {
+    pnerr= illegal_packagename(value,0);
+    if (pnerr) ohshite("--ignore-depends requires a legal package name. "
+                       "`%.250s' is not; %s", value, pnerr);
+    ni= m_malloc(sizeof(struct packageinlist));
+    ni->pkg= findpackage(value);
+    ni->next= ignoredependss;
+    ignoredependss= ni;
+    p+= strlen(p)+1;
+  }
+}
+
+static void setforce(const struct cmdinfo *cip, const char *value) {
+  const char *comma;
+  int l;
+  const struct forceinfo *fip;
+
+  if (!strcmp(value,"help")) {
+    if (!fputs(
+DPKG " forcing options - control behaviour when problems found:\n\
+  warn but continue:  --force-<thing>,<thing>,...\n\
+  stop with error:    --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n\
+ Forcing things:\n\
+  auto-select [*]        (De)select packages to install (remove) them\n\
+  dowgrade [*]           Replace a package with a lower version\n\
+  configure-any          Configure any package which may help this one\n\
+  hold                   Process packages which are on hold\n\
+  bad-path               PATH is missing important programs, problems likely\n\
+  overwrite              Overwrite a file from one package with another\n\
+  overwrite-diverted     Overwrite a diverted file with an undiverted version\n\
+  depends-version [!]    Turn dependency version problems into warnings\n\
+  depends [!]            Turn all dependency problems into warnings\n\
+  conflicts [!]          Allow installation of conflicting packages\n\
+  architecture [!]       Process even packages with wrong architecture\n\
+  remove-reinstreq [!]   Remove packages which require installation\n\
+  remove-essential [!]   Remove an essential package\n\
+\n\
+WARNING - use of options marked [!] can seriously damage your installation.\n\
+Forcing options marked [*] are enabled by default.\n",
+               stderr)) werr("stderr");
+    exit(0);
+  }
+
+  for (;;) {
+    comma= strchr(value,',');
+    l= comma ? (int)(comma-value) : strlen(value);
+    for (fip=forceinfos; fip->name; fip++)
+      if (!strncmp(fip->name,value,l) && strlen(fip->name)==l) break;
+    if (!fip->name)
+      badusage("unknown force/refuse option `%.*s'", l<250 ? l : 250, value);
+    *fip->opt= cip->arg;
+    if (!comma) break;
+    value= ++comma;
+  }
+}
+
+static const char *const passlongopts[]= {
+  "build", "contents", "control", "info", "field", "extract",
+  "vextract", "fsys-tarfile", 0
+};
+
+static const char passshortopts[]= "bceIfxX";
+static const char okpassshortopts[]= "D";
+
+static const struct cmdinfo cmdinfos[]= {
+  { "install",           'i',  0,  0, 0,               setaction,     act_install    },
+  { "unpack",             0,   0,  0, 0,               setaction,     act_unpack     },
+  { "avail",             'A',  0,  0, 0,               setaction,     act_avail      },
+  { "configure",          0,   0,  0, 0,               setaction,     act_configure  },
+  { "remove",            'r',  0,  0, 0,               setaction,     act_remove     },
+  { "purge",              0,   0,  0, 0,               setaction,     act_purge      },
+  { "list",              'l',  0,  0, 0,               setaction,     act_list       },
+  { "status",            's',  0,  0, 0,               setaction,     act_status     },
+  { "search",            'S',  0,  0, 0,               setaction,     act_search     },
+  { "audit",             'C',  0,  0, 0,               setaction,     act_audit      },
+  { "listfiles",         'L',  0,  0, 0,               setaction,     act_listfiles  },
+  { "update-avail",       0,   0,  0, 0,               setaction,     act_avreplace  },
+  { "merge-avail",        0,   0,  0, 0,               setaction,     act_avmerge    },
+  { "yet-to-unpack",      0,   0,  0, 0,               setaction,     act_unpackchk  },
+  { "assert-support-predepends", 0, 0,  0, 0,          setaction,    act_assuppredep },
+  { "print-architecture", 0,   0,  0, 0,               setaction,     act_printarch  },
+  { "predep-package",     0,   0,  0, 0,               setaction,  act_predeppackage },
+  { "pending",           'a',  0,  &f_pending,     0,  0,             1              },
+  { "recursive",         'R',  0,  &f_recursive,   0,  0,             1              },
+  { "no-act",             0,   0,  &f_noact,       0,  0,             1              },
+  {  0,                  'G',  0,  &fc_downgrade,  0,  0, /* alias for --refuse */ 0 },
+  { "selected-only",     'O',  0,  &f_alsoselect,  0,  0,             0              },
+  { "no-also-select",  'N', 0, &f_alsoselect, 0, 0, 0 /* fixme: remove eventually */ },
+  { "skip-same-version", 'E',  0,  &f_skipsame,    0,  0,             1              },
+  { "auto-deconfigure",  'B',  0,  &f_autodeconf,  0,  0,             1              },
+  { "largemem",           0,   0,  &f_largemem,    0,  0,             1              },
+  { "smallmem",           0,   0,  &f_largemem,    0,  0,            -1              },
+  { "root",               0,   1,  0, 0,               setroot                       },
+  { "admindir",           0,   1,  0, &admindir,       0                             },
+  { "instdir",            0,   1,  0, &instdir,        0                             },
+  { "ignore-depends",     0,   1,  0, 0,               ignoredepends                 },
+  { "force",              0,   2,  0, 0,               setforce,      1              },
+  { "refuse",             0,   2,  0, 0,               setforce,      0              },
+  { "no-force",           0,   2,  0, 0,               setforce,      0              },
+  { "debug",             'D',  1,  0, 0,               setdebug                      },
+  { "help",              'h',  0,  0, 0,               helponly                      },
+  { "version",            0,   0,  0, 0,               versiononly                   },
+  { "licence",/* UK spelling */ 0,0,0,0,               showcopyright                 },
+  { "license",/* US spelling */ 0,0,0,0,               showcopyright                 },
+  {  0,                   0                                                          }
+};
+
+static void execbackend(int argc, const char *const *argv) {
+  execvp(BACKEND, (char* const*) argv);
+  ohshite("failed to exec " BACKEND);
+}
+
+int main(int argc, const char *const *argv) {
+  jmp_buf ejbuf;
+  int c;
+  const char *argp, *const *blongopts, *const *argvs;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  umask(022); /* Make sure all our status databases are readable. */
+  
+  for (argvs=argv+1; (argp= *argvs) && *argp++=='-'; argvs++) {
+    if (*argp++=='-') {
+      if (!strcmp(argp,"-")) break;
+      for (blongopts=passlongopts; *blongopts; blongopts++) {
+        if (!strcmp(argp,*blongopts)) execbackend(argc,argv);
+      }
+    } else {
+      if (!*--argp) break;
+      while ((c= *argp++)) {
+        if (strchr(passshortopts,c)) execbackend(argc,argv);
+        if (!strchr(okpassshortopts,c)) break;
+      }
+    }
+  }
+
+  myopt(&argv,cmdinfos);
+  if (!cipaction) badusage("need an action option");
+
+  setvbuf(stdout,0,_IONBF,0);
+  filesdbinit();
+  
+  switch (cipaction->arg) {
+  case act_install: case act_unpack: case act_avail:
+    checkpath();
+    archivefiles(argv);
+    break;
+  case act_configure: case act_remove: case act_purge:
+    checkpath();
+    packages(argv);
+    break;
+  case act_listfiles: case act_status:
+    enqperpackage(argv);
+    break;
+  case act_avreplace: 
+    availablefrompackages(argv,1);
+    break;
+  case act_avmerge:
+    availablefrompackages(argv,0);
+    break;
+  case act_audit:
+    audit(argv);
+    break;
+  case act_unpackchk:
+    unpackchk(argv);
+    break;
+  case act_list:
+    listpackages(argv);
+    break;
+  case act_search:
+    searchfiles(argv);
+    break;
+  case act_assuppredep:
+    assertsupportpredepends(argv);
+    break;
+  case act_predeppackage:
+    predeppackage(argv);
+    break;
+  case act_printarch:
+    printarchitecture(argv);
+    break;
+  default:
+    internerr("unknown action");
+  }
+
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+
+  return reportbroken_retexitstatus();
+}
diff --git a/main/main.h b/main/main.h
new file mode 100644 (file)
index 0000000..21a1f9c
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * dpkg - main program for package management
+ * dpkg-deb.h - external definitions for this program
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+struct fileinlist; /* these two are defined in filesdb.h */
+struct filenamenode;
+
+struct perpackagestate {
+  enum istobes {
+    itb_normal, itb_remove, itb_installnew, itb_deconfigure, itb_preinstall
+  } istobe;
+
+  /*   filelistvalid   files         meaning
+   *       0             0           not read yet, must do so if want them
+   *       0            !=0          read, but rewritten and now out of
+   *                               date.  If want info must throw away old
+   *                               and reread file.
+   *       1            !=0          read, all is OK
+   *       1             0           read OK, but, there were no files
+   */
+  int fileslistvalid;
+  struct fileinlist *files;
+  int replacingfilesandsaid;
+};
+
+struct packageinlist {
+  struct packageinlist *next;
+  struct pkginfo *pkg;
+};
+
+enum action { act_unset, act_install, act_unpack, act_avail, act_configure,
+              act_remove, act_purge, act_list, act_avreplace, act_avmerge,
+              act_unpackchk, act_status, act_search, act_audit, act_listfiles,
+              act_assuppredep, act_printarch, act_predeppackage };
+
+enum conffopt {
+  cfof_prompt        =     001,
+  cfof_keep          =     002,
+  cfof_install       =     004,
+  cfof_backup        =    0100,
+  cfof_newconff      =    0200,
+  cfof_isnew         =    0400,
+  cfom_main          =     007,
+  cfo_keep           =   cfof_keep,
+  cfo_prompt_keep    =   cfof_keep | cfof_prompt,
+  cfo_prompt         =               cfof_prompt,
+  cfo_prompt_install =               cfof_prompt | cfof_install,
+  cfo_install        =                             cfof_install,
+  cfo_newconff       =                             cfof_install | cfof_newconff,
+  cfo_identical      =   cfof_keep
+};
+
+extern int conffoptcells[2][2];
+extern const char *const statusstrings[];
+
+extern const struct cmdinfo *cipaction;
+extern int f_pending, f_recursive, f_alsoselect, f_skipsame, f_noact;
+extern int f_autodeconf, f_largemem;
+extern unsigned long f_debug;
+extern int fc_downgrade, fc_configureany, fc_hold, fc_removereinstreq, fc_overwrite;
+extern int fc_removeessential, fc_conflicts, fc_depends, fc_dependsversion;
+extern int fc_autoselect, fc_badpath, fc_overwritediverted, fc_architecture;
+
+extern const char *admindir;
+extern const char *instdir;
+extern struct packageinlist *ignoredependss;
+extern const char architecture[];
+
+/* from filesdb.c */
+
+void filesdbinit(void);
+
+/* from archives.c */
+
+void archivefiles(const char *const *argv);
+void process_archive(const char *filename);
+
+/* from update.c */
+
+void availablefrompackages(const char *const *argv, int replace);
+
+/* from enquiry.c */
+
+void listpackages(const char *const *argv);
+void audit(const char *const *argv);
+void unpackchk(const char *const *argv);
+void searchfiles(const char *const *argv);
+void enqperpackage(const char *const *argv);
+void assertsupportpredepends(const char *const *argv);
+void predeppackage(const char *const *argv);
+void printarchitecture(const char *const *argv);
+
+/* from packages.c, remove.c and configure.c */
+
+void add_to_queue(struct pkginfo *pkg);
+void process_queue(void);
+void packages(const char *const *argv);
+void removal_bulk(struct pkginfo *pkg);
+int conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in);
+int dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
+                    struct varbuf *aemsgs);
+
+void deferred_remove(struct pkginfo *pkg);
+void deferred_configure(struct pkginfo *pkg);
+
+extern int queuelen, sincenothing, dependtry;
+
+/* from cleanup.c (most of these are declared in archives.h) */
+
+void cu_prermremove(int argc, void **argv);
+
+/* from errors.c */
+
+void print_error_perpackage(const char *emsg, const char *arg);
+void forcibleerr(int forceflag, const char *format, ...) PRINTFFORMAT(2,3);
+int reportbroken_retexitstatus(void);
+int skip_due_to_hold(struct pkginfo *pkg);
+
+/* from help.c */
+
+void cu_closefile(int argc, void **argv);
+void cu_closepipe(int argc, void **argv);
+void cu_closedir(int argc, void **argv);
+void cu_closefd(int argc, void **argv);
+
+int ignore_depends(struct pkginfo *pkg);
+int force_depends(struct deppossi *possi);
+int force_conflicts(struct deppossi *possi);
+void ensure_package_clientdata(struct pkginfo *pkg);
+const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile);
+void oldconffsetflags(struct conffile *searchconff);
+void ensure_pathname_nonexisting(const char *pathname);
+void checkpath(void);
+struct filenamenode *namenodetouse(struct filenamenode*, struct pkginfo*);
+
+/* all ...'s are const char*'s ... */
+int maintainer_script_installed(struct pkginfo *pkg, const char *scriptname,
+                                const char *description, ...);
+int maintainer_script_new(const char *scriptname, const char *description,
+                          const char *cidir, char *cidirrest, ...);
+int maintainer_script_alternative(struct pkginfo *pkg,
+                                  const char *scriptname, const char *description,
+                                  const char *cidir, char *cidirrest,
+                                  const char *ifok, const char *iffallback);
+void clear_istobes(void);
+int isdirectoryinuse(struct filenamenode *namenode, struct pkginfo *pkg);
+
+enum debugflags {
+  dbg_general=           00001,
+  dbg_scripts=           00002,
+  dbg_eachfile=          00010,
+  dbg_eachfiledetail=    00100,
+  dbg_conff=             00020,
+  dbg_conffdetail=       00200,
+  dbg_depcon=            00040,
+  dbg_depcondetail=      00400,
+  dbg_veryverbose=       01000,
+  dbg_stupidlyverbose=   02000,
+};
+  
+void debug(int which, const char *fmt, ...) PRINTFFORMAT(2,3);
+
+/* from depcon.c */
+
+int depisok(struct dependency *dep, struct varbuf *whynot,
+            struct pkginfo **fixbyrm, int allowunconfigd);
+const char *versiondescribe(const char *ver, const char *rev);
+struct cyclesofarlink;
+int findbreakcycle(struct pkginfo *pkg, struct cyclesofarlink *sofar);
+void describedepcon(struct varbuf *addto, struct dependency *dep);
+
+int versionsatisfied(struct pkginfoperfile *it, struct deppossi *against);
+int versionsatisfied5(const char *itver, const char *itrev,
+                      const char *refver, const char *refrev,
+                      enum depverrel verrel);
+
+#endif /* MAIN_H */
diff --git a/main/packages.c b/main/packages.c
new file mode 100644 (file)
index 0000000..1db2db0
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * dpkg - main program for package management
+ * packages.c - common to actions that process packages
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+struct pkginqueue {
+  struct pkginqueue *next;
+  struct pkginfo *pkg;
+};
+
+static struct pkginqueue *queuehead= 0, **queuetail= &queuehead;
+
+int queuelen=0, sincenothing=0, dependtry=0;
+
+void add_to_queue(struct pkginfo *pkg) {
+  struct pkginqueue *newent;
+
+  newent= m_malloc(sizeof(struct pkginqueue));
+  newent->pkg= pkg;
+  newent->next= 0;
+  *queuetail= newent;
+  queuetail= &newent->next;
+
+  queuelen++;
+}
+
+void packages(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  const char *thisarg;
+  int l;
+  
+  modstatdb_init(admindir, f_noact ? msdbrw_readonly : msdbrw_needsuperuser);
+
+  if (f_pending) {
+
+    if (*argv)
+      badusage("--%s --pending does not take any non-option arguments",cipaction->olong);
+
+    it= iterpkgstart();
+    while ((pkg= iterpkgnext(it)) != 0) {
+      switch (cipaction->arg) {
+      case act_configure:
+        if (pkg->status != stat_unpacked && pkg->status != stat_halfconfigured)
+          continue;
+        if (pkg->want != want_install)
+          continue;
+        break;
+      case act_remove:
+      case act_purge:
+        if (pkg->want != want_purge) {
+          if (pkg->want != want_deinstall) continue;
+          if (pkg->status == stat_configfiles) continue;
+        }
+        if (pkg->status == stat_notinstalled)
+          continue;
+        break;
+      default:
+        internerr("unknown action for pending");
+      }
+      add_to_queue(pkg);
+    }
+    iterpkgend(it);
+
+  } else {
+        
+    if (!*argv)
+      badusage("--%s needs at least one package name argument", cipaction->olong);
+    
+    while ((thisarg= *argv++) != 0) {
+      pkg= findpackage(thisarg);
+      if (pkg->status == stat_notinstalled) {
+        l= strlen(pkg->name);
+        if (l >= sizeof(DEBEXT) && !strcmp(pkg->name+l-sizeof(DEBEXT)+1,DEBEXT))
+          badusage("you must specify packages by their own names,"
+                   " not by quoting the names of the files they come in");
+      }
+      add_to_queue(pkg);
+    }
+
+  }
+
+  ensure_diversions();
+
+  process_queue();
+
+  modstatdb_shutdown();
+}
+
+void process_queue(void) {
+  struct pkginqueue *removeent, *rundown;
+  struct pkginfo *volatile pkg;
+  jmp_buf ejbuf;
+  enum istobes istobe;
+  
+  clear_istobes();
+
+  switch (cipaction->arg) {
+  case act_configure: case act_install:  istobe= itb_installnew;  break;
+  case act_remove: case act_purge:       istobe= itb_remove;      break;
+  default: internerr("unknown action for queue start");
+  }
+  for (rundown= queuehead; rundown; rundown= rundown->next) {
+    ensure_package_clientdata(rundown->pkg);
+    if (rundown->pkg->clientdata->istobe == istobe) {
+      /* Remove it from the queue - this is a second copy ! */
+      switch (cipaction->arg) {
+      case act_configure: case act_remove: case act_purge:
+        printf("Package %s listed more than once, only processing once.\n",
+               rundown->pkg->name);
+        break;
+      case act_install:
+        printf("More than one copy of package %s has been unpacked\n"
+               " in this run !  Only configuring it once.\n",
+               rundown->pkg->name);
+        break;
+      default:
+        internerr("unknown action in duplicate");
+      }
+      rundown->pkg= 0;
+   } else {
+      rundown->pkg->clientdata->istobe= istobe;
+    }
+  }
+  
+  while (queuelen) {
+    removeent= queuehead;
+    assert(removeent);
+    queuehead= queuehead->next;
+    queuelen--;
+    if (queuetail == &removeent->next) queuetail= &queuehead;
+
+    pkg= removeent->pkg;
+    free(removeent);
+    
+    if (!pkg) continue; /* duplicate, which we removed earlier */
+
+    if (skip_due_to_hold(pkg)) { pkg->clientdata->istobe= itb_normal; continue; }
+    
+    assert(pkg->status <= stat_configfiles);
+
+    if (setjmp(ejbuf)) {
+      /* give up on it from the point of view of other packages, ie reset istobe */
+      pkg->clientdata->istobe= itb_normal;
+      error_unwind(ehflag_bombout);
+      if (onerr_abort > 0) break;
+      continue;
+    }
+    push_error_handler(&ejbuf,print_error_perpackage,pkg->name);
+    if (sincenothing++ > queuelen*2+2) {
+      dependtry++; sincenothing= 0;
+      assert(dependtry <= 4);
+    }
+    switch (cipaction->arg) {
+    case act_configure:
+    case act_install:
+      deferred_configure(pkg);
+      break;
+    case act_remove: case act_purge:
+      deferred_remove(pkg);
+      break;
+    default:
+      internerr("unknown action in queue");
+    }
+    if (ferror(stdout)) werr("stdout");
+    if (ferror(stderr)) werr("stderr");
+    set_error_display(0,0);
+    error_unwind(ehflag_normaltidy);
+  }
+}    
+
+/*** dependency processing - common to --configure and --remove ***/
+
+/*
+ * The algorithm for deciding what to configure or remove first is as
+ * follows:
+ *
+ * Loop through all packages doing a `try 1' until we've been round and
+ * nothing has been done, then do `try 2' and `try 3' likewise.
+ *
+ * When configuring, in each try we check to see whether all
+ * dependencies of this package are done.  If so we do it.  If some of
+ * the dependencies aren't done yet but will be later we defer the
+ * package, otherwise it is an error.
+ *
+ * When removing, in each try we check to see whether there are any
+ * packages that would have dependencies missing if we removed this
+ * one.  If not we remove it now.  If some of these packages are
+ * themselves scheduled for removal we defer the package until they
+ * have been done.
+ *
+ * The criteria for satisfying a dependency vary with the various
+ * tries.  In try 1 we treat the dependencies as absolute.  In try 2 we
+ * check break any cycles in the dependency graph involving the package
+ * we are trying to process before trying to process the package
+ * normally.  In try 3 (which should only be reached if
+ * --force-depends-version is set) we ignore version number clauses in
+ * Depends lines.  In try 4 (only reached if --force-depends is set) we
+ * say "ok" regardless.
+ *
+ * If we are configuring and one of the packages we depend on is
+ * awaiting configuration but wasn't specified in the argument list we
+ * will add it to the argument list if --configure-any is specified.
+ * In this case we note this as having "done something" so that we
+ * don't needlessly escalate to higher levels of dependency checking
+ * and breaking.
+ */
+
+static int deppossi_ok_found(struct pkginfo *possdependee,
+                             struct pkginfo *requiredby,
+                             struct pkginfo *removing,
+                             int *matched,
+                             struct deppossi *checkversion,
+                             int *interestingwarnings,
+                             struct varbuf *oemsgs) {
+  int thisf;
+  
+  if (ignore_depends(possdependee)) {
+    debug(dbg_depcondetail,"      ignoring depended package so ok and found");
+    return 3;
+  }
+  thisf= 0;
+  if (possdependee == removing) {
+    varbufaddstr(oemsgs,"  Package ");
+    varbufaddstr(oemsgs,possdependee->name);
+    varbufaddstr(oemsgs," is to be removed.\n");
+    *matched= 1;
+    if (fc_depends) thisf= (dependtry >= 4) ? 2 : 1;
+    debug(dbg_depcondetail,"      removing possdependee, returning %d",thisf);
+    return thisf;
+  }
+  switch (possdependee->status) {
+  case stat_installed:
+  case stat_unpacked:
+  case stat_halfconfigured:
+    assert(possdependee->installed.valid);
+    if (checkversion && !versionsatisfied(&possdependee->installed,checkversion)) {
+      varbufaddstr(oemsgs,"  Version of ");
+      varbufaddstr(oemsgs,possdependee->name);
+      varbufaddstr(oemsgs," on system is ");
+      varbufaddstr(oemsgs,versiondescribe(possdependee->installed.version,
+                                           possdependee->installed.revision));
+      varbufaddstr(oemsgs,".\n");
+      assert(checkversion->verrel != dvr_none);
+      if (fc_depends) thisf= (dependtry >= 3) ? 2 : 1;
+      debug(dbg_depcondetail,"      bad version, returning %d",thisf);
+      (*interestingwarnings)++;
+      return thisf;
+    }
+    if (possdependee->status == stat_installed) {
+      debug(dbg_depcondetail,"      is installed, ok and found");
+      return 3;
+    }
+    if (possdependee->clientdata &&
+        possdependee->clientdata->istobe == itb_installnew) {
+      debug(dbg_depcondetail,"      unpacked/halfconfigured, defer");
+      return 1;
+    } else if (!removing && fc_configureany) {
+      fprintf(stderr, DPKG
+              ": also configuring `%s' (required by `%s')\n",
+              possdependee->name, requiredby->name);
+      add_to_queue(possdependee); sincenothing=0; return 1;
+    } else {
+      varbufaddstr(oemsgs,"  Package ");
+      varbufaddstr(oemsgs,possdependee->name);
+      varbufaddstr(oemsgs," is not configured yet.\n");
+      if (fc_depends) thisf= (dependtry >= 4) ? 2 : 1;
+      debug(dbg_depcondetail,"      not configured/able - returning %d",thisf);
+      (*interestingwarnings)++;
+      return thisf;
+    }
+  default:
+    varbufaddstr(oemsgs,"  Package ");
+    varbufaddstr(oemsgs,possdependee->name);
+    varbufaddstr(oemsgs," is not installed.\n");
+    if (fc_depends) thisf= (dependtry >= 4) ? 2 : 1;
+    debug(dbg_depcondetail,"      not installed - returning %d",thisf);
+    (*interestingwarnings)++;
+    return thisf;
+  }
+}
+
+int dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
+                    struct varbuf *aemsgs) {
+  int ok, matched, found, thisf, interestingwarnings;
+  struct varbuf oemsgs;
+  struct dependency *dep;
+  struct deppossi *possi, *provider;
+
+  varbufinit(&oemsgs);
+  interestingwarnings= 0;
+  ok= 2; /* 2=ok, 1=defer, 0=halt */
+  debug(dbg_depcon,"checking dependencies of %s (- %s)",
+        pkg->name, removing ? removing->name : "<none>");
+  assert(pkg->installed.valid);
+  for (dep= pkg->installed.depends; dep; dep= dep->next) {
+    if (dep->type != dep_depends && dep->type != dep_predepends) continue;
+    debug(dbg_depcondetail,"  checking group ...");
+    matched= 0; varbufreset(&oemsgs);
+    found= 0; /* 0=none, 1=defer, 2=withwarning, 3=ok */
+    for (possi= dep->list; found != 3 && possi; possi= possi->next) {
+      debug(dbg_depcondetail,"    checking possibility  -> %s",possi->ed->name);
+      if (possi->cyclebreak) {
+        debug(dbg_depcondetail,"      break cycle so ok and found");
+        found= 3; break;
+      }
+      thisf= deppossi_ok_found(possi->ed,pkg,removing,
+                               &matched,possi,&interestingwarnings,&oemsgs);
+      if (thisf > found) found= thisf;
+      if (found != 3 && possi->verrel == dvr_none) {
+        if (possi->ed->installed.valid) {
+          for (provider= possi->ed->installed.depended;
+               found != 3 && provider;
+               provider= provider->nextrev) {
+            if (provider->up->type != dep_provides) continue;
+            debug(dbg_depcondetail,"     checking provider %s",provider->up->up->name);
+            thisf= deppossi_ok_found(provider->up->up,pkg,removing,
+                                     &matched,0,&interestingwarnings,&oemsgs);
+            if (thisf > found) found= thisf;
+          }
+        }
+      }
+      debug(dbg_depcondetail,"    found %d",found);
+      if (thisf > found) found= thisf;
+    }
+    debug(dbg_depcondetail,"  found %d matched %d",found,matched);
+    if (removing && !matched) continue;
+    switch (found) {
+    case 0:
+      ok= 0;
+    case 2:
+      varbufaddstr(aemsgs, " ");
+      varbufaddstr(aemsgs, pkg->name);
+      varbufaddstr(aemsgs, " depends on ");
+      varbufdependency(aemsgs, dep);
+      if (interestingwarnings) {
+        /* Don't print the line about the package to be removed if
+         * that's the only line.
+         */
+        varbufaddstr(aemsgs, "; however:\n");
+        varbufaddc(&oemsgs, 0);
+        varbufaddstr(aemsgs, oemsgs.buf);
+      } else {
+        varbufaddstr(aemsgs, ".\n");
+      }
+      break;
+    case 1:
+      if (ok>1) ok= 1;
+      break;
+    case 3:
+      break;
+    default:
+      internerr("unknown value for found");
+    }
+  }
+  if (ok == 0 && (pkg->clientdata && pkg->clientdata->istobe == itb_remove))
+    ok= 1;
+  
+  varbuffree(&oemsgs);
+  debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, aemsgs->used, aemsgs->buf);
+  return ok;
+}
diff --git a/main/processarc.c b/main/processarc.c
new file mode 100644 (file)
index 0000000..2df3d0d
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * dpkg - main program for package management
+ * processarc.c - the huge function process_archive
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <assert.h>
+#include <time.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+#include "tarfn.h"
+
+#include "filesdb.h"
+#include "main.h"
+#include "archives.h"
+
+void process_archive(const char *filename) {
+  static const struct TarFunctions tf = {
+    tarfileread,
+    tarobject, tarobject, tarobject, tarobject, tarobject
+  };
+
+  /* These need to be static so that we can pass their addresses to
+   * push_cleanup as arguments to the cu_xxx routines; if an error occurs
+   * we unwind the stack before processing the cleanup list, and these
+   * variables had better still exist ...
+   */
+  static int p1[2];
+  static char cidirtmpnambuf[L_tmpnam+100];
+  static char *cidirbuf=0, *reasmbuf=0;
+  static struct fileinlist *newconffiles;
+  static enum pkgstatus oldversionstatus;
+  static struct varbuf infofnvb, fnvb, depprobwhy;
+  static struct tarcontext tc;
+  
+  int c1, r, admindirlen, i, infodirlen, infodirbaseused, status;
+  struct pkgiterator *it;
+  struct pkginfo *pkg, *conflictor, *otherpkg, *divpkg;
+  char *cidir, *cidirrest, *p;
+  char pfilenamebuf[50], conffilenamebuf[MAXCONFFILENAME];
+  const char *pfilename, *newinfofilename;
+  struct fileinlist *newconff, **newconffileslastp, *newfileslist;
+  struct fileinlist *cfile;
+  struct reversefilelistiter rlistit;
+  struct conffile *searchconff, **iconffileslastp, *newiconff;
+  struct filepackages *packageslump;
+  struct dependency *dsearch, *newdeplist, **newdeplistlastp;
+  struct dependency *newdep, *dep, *providecheck;
+  struct deppossi *psearch, **newpossilastp, *possi, *newpossi, *pdep;
+  FILE *conff, *tmpf;
+  DIR *dsd;
+  struct filenamenode *namenode;
+  struct dirent *de;
+  struct stat stab;
+  struct packageinlist *deconpil, *deconpiltemp;
+
+  cleanup_pkg_failed= cleanup_conflictor_failed= 0;
+  admindirlen= strlen(admindir);
+
+  pfilename= filename;
+  while (strlen(pfilename) > sizeof(pfilenamebuf)-5) {
+    pfilename= strchr(pfilename,'/');
+    if (!pfilename) break;
+    pfilename++;
+  }
+  if (pfilename && pfilename != filename) {
+    strcpy(pfilenamebuf,".../");
+    strcat(pfilenamebuf,pfilename);
+    pfilename= pfilenamebuf;
+  } else {
+    pfilename= filename;
+  }
+
+  if (!f_noact) {
+    /* We can't `tentatively-reassemble' packages. */
+    if (!reasmbuf) {
+      reasmbuf= m_malloc(admindirlen+sizeof(REASSEMBLETMP)+5);
+      strcpy(reasmbuf,admindir);
+      strcat(reasmbuf,"/" REASSEMBLETMP);
+    }
+    if (unlink(reasmbuf) && errno != ENOENT)
+      ohshite("error ensuring `%.250s' doesn't exist",reasmbuf);
+    push_cleanup(cu_pathname,~0, 0,0, 1,(void*)reasmbuf);
+    c1= m_fork();
+    if (!c1) {
+      execlp(SPLITTER, SPLITTER,"-Qao",reasmbuf,filename,(char*)0);
+      ohshite("failed to exec " SPLITTER " to see if it's part of a multiparter");
+    }
+    while ((r= waitpid(c1,&status,0)) == -1 && errno == EINTR);
+    if (r != c1) { onerr_abort++; ohshite("wait for " SPLITTER " failed"); }
+    switch (WIFEXITED(status) ? WEXITSTATUS(status) : -1) {
+    case 0:
+      /* It was a part - is it complete ? */
+      if (!stat(reasmbuf,&stab)) { /* Yes. */
+        filename= reasmbuf;
+        pfilename= "reassembled package file";
+        break;
+      } else if (errno == ENOENT) { /* No.  That's it, we skip it. */
+        return;
+      }
+    case 1:
+      /* No, it wasn't a part. */
+      break;
+    default:
+      checksubprocerr(status,SPLITTER,0);
+    }
+  }
+  
+  if (f_noact) {
+    cidir= cidirtmpnambuf;
+    if (!tmpnam(cidir)) ohshite("unable to get unique filename for control info");
+    strcat(cidir,"/");
+  } else {
+    /* We want it to be on the same filesystem so that we can
+     * use rename(2) to install the postinst &c.
+     */
+    if (!cidirbuf)
+      cidirbuf= m_malloc(admindirlen+sizeof(CONTROLDIRTMP)+MAXCONTROLFILENAME+10);
+    cidir= cidirbuf;
+    strcpy(cidir,admindir);
+    strcat(cidir, "/" CONTROLDIRTMP);
+  }
+  cidirrest= cidir + strlen(cidir);
+
+  assert(*cidir && cidirrest[-1] == '/'); cidirrest[-1]= 0;
+  ensure_pathname_nonexisting(cidir); cidirrest[-1]= '/';
+  
+  push_cleanup(cu_cidir,~0, 0,0, 2,(void*)cidir,(void*)cidirrest);
+  c1= m_fork();
+  if (!c1) {
+    cidirrest[-1]= 0;
+    execlp(BACKEND, BACKEND,"--control",filename,cidir,(char*)0);
+    ohshite("failed to exec " BACKEND " to extract control information");
+  }
+  waitsubproc(c1,BACKEND " --control",0);
+  strcpy(cidirrest,CONTROLFILE);
+
+  parsedb(cidir, pdb_recordavailable|pdb_rejectstatus|pdb_weakclassification,
+          &pkg,0,0);
+
+  if (cipaction->arg == act_avail) {
+    printf("Read updated information about %s from %s.\n",pkg->name,pfilename);
+    pop_cleanup(ehflag_normaltidy);
+    return;
+  }
+
+  if (pkg->available.architecture && *pkg->available.architecture &&
+      strcmp(pkg->available.architecture,"all") &&
+      strcmp(pkg->available.architecture,architecture))
+    forcibleerr(fc_architecture,
+                "package architecture (%s) does not match system (%s)",
+                pkg->available.architecture,architecture);
+    
+  if (skip_due_to_hold(pkg)) { pop_cleanup(ehflag_normaltidy); return; }
+  
+  if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
+  assert(pkg->available.valid);
+
+  for (deconpil= deconfigure;
+       deconpil;
+       deconpil= deconpiltemp) {
+    deconpiltemp= deconpil->next;
+    free(deconpil);
+  }
+  deconfigure= 0;
+  clear_istobes();
+
+  if (pkg->want != want_install) {
+    if (f_alsoselect) {
+      printf("Selecting previously deselected package %s.\n",pkg->name);
+      pkg->want= want_install;
+    } else {
+      printf("Skipping deselected package %s.\n",pkg->name);
+      return;
+    }
+  }
+
+  if (pkg->status == stat_installed) {
+    r= versioncompare(pkg->available.version,pkg->available.revision,
+                      pkg->installed.version,pkg->installed.revision);
+    if (r < 0) {
+      if (fc_downgrade) {
+        fprintf(stderr, DPKG " - warning: downgrading %.250s from %.250s to %.250s.\n",
+                pkg->name,
+                versiondescribe(pkg->installed.version,pkg->installed.revision),
+                versiondescribe(pkg->available.version,pkg->available.revision));
+      } else {
+        fprintf(stderr, "Will not downgrade"
+                " %.250s from version %.250s to %.250s, skipping.\n",
+                pkg->name,
+                versiondescribe(pkg->installed.version,pkg->installed.revision),
+                versiondescribe(pkg->available.version,pkg->available.revision));
+        pop_cleanup(ehflag_normaltidy);
+        return;
+      }
+    } else if (r == 0 && f_skipsame && /* same version fully installed ? */
+               pkg->status == stat_installed && !(pkg->eflag &= eflagf_reinstreq)) {
+      fprintf(stderr, "Version %.250s of %.250s already installed, skipping.\n",
+              versiondescribe(pkg->installed.version,pkg->installed.revision),
+              pkg->name);
+      pop_cleanup(ehflag_normaltidy);
+      return;
+    }
+  }
+
+  pkg->clientdata->istobe= itb_installnew;
+  conflictor= 0;
+  for (dsearch= pkg->available.depends; dsearch; dsearch= dsearch->next) {
+    switch (dsearch->type) {
+    case dep_conflicts:
+      /* Look for things we conflict with. */
+      check_conflict(dsearch, pkg, pfilename, &conflictor);
+      break;
+    case dep_provides:
+      /* Look for things that conflict with what we provide. */
+      if (dsearch->list->ed->installed.valid) {
+        for (psearch= dsearch->list->ed->installed.depended;
+             psearch;
+             psearch= psearch->nextrev) {
+          if (psearch->up->type != dep_conflicts) continue;
+          check_conflict(psearch->up, pkg, pfilename, &conflictor);
+        }
+      }
+      break;
+    case dep_suggests: case dep_recommends: case dep_depends: case dep_replaces:
+      /* Ignore these here. */
+      break;
+    case dep_predepends:
+      if (!depisok(dsearch,&depprobwhy,0,1)) {
+        varbufaddc(&depprobwhy,0);
+        fprintf(stderr, DPKG ": regarding %s containing %s, pre-dependency problem:\n%s",
+                pfilename, pkg->name, depprobwhy.buf);
+        if (!force_depends(dsearch->list))
+          ohshit("pre-dependency problem - not installing %.250s",pkg->name);
+        fprintf(stderr, DPKG ": warning - ignoring pre-dependency problem !\n");
+      }
+    }
+  }
+  /* Look for things that conflict with us. */
+  for (psearch= pkg->installed.depended; psearch; psearch= psearch->nextrev) {
+    if (psearch->up->type != dep_conflicts) continue;
+    check_conflict(psearch->up, pkg, pfilename, &conflictor);
+  }
+  
+  ensure_allinstfiles_available();
+  filesdbinit();
+  
+  if (pkg->status != stat_notinstalled && pkg->status != stat_configfiles)
+    printf("Preparing to replace %s (using %s) ...\n",pkg->name,pfilename);
+  else
+    printf("Unpacking %s (from %s) ...\n",pkg->name,pfilename);
+
+  if (f_noact) {
+    pop_cleanup(ehflag_normaltidy);
+    return;
+  }
+
+  /* OK, we're going ahead.  First we read the conffiles, and copy the
+   * hashes across.
+   */
+  newconffiles= 0; newconffileslastp= &newconffiles;
+  push_cleanup(cu_fileslist,~0, 0,0, 1,(void*)&newconffiles);
+  strcpy(cidirrest,CONFFILESFILE);
+  conff= fopen(cidir,"r");
+  if (conff) {
+    push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)conff);
+    while (fgets(conffilenamebuf,MAXCONFFILENAME-2,conff)) {
+      p= conffilenamebuf + strlen(conffilenamebuf);
+      assert(p != conffilenamebuf);
+      if (p[-1] != '\n')
+        ohshit("name of conffile (starting `%.250s') is too long (>%d characters)",
+               conffilenamebuf, MAXCONFFILENAME);
+      while (p > conffilenamebuf && isspace(p[-1])) --p;
+      if (p == conffilenamebuf) continue;
+      *p= 0;
+      newconff= m_malloc(sizeof(struct fileinlist));
+      newconff->next= 0;
+      newconff->namenode= findnamenode(conffilenamebuf);
+      *newconffileslastp= newconff;
+      newconffileslastp= &newconff->next;
+      newconff->namenode->oldhash= NEWCONFFILEFLAG;
+      /* Let's see if any packages have this file.  If they do we
+       * check to see if they listed it as a conffile, and if they did
+       * we copy the hash across.  Since (for plain file conffiles,
+       * which is the only kind we are supposed to have) there will
+       * only be one package which `has' the file, this will usually
+       * mean we only look in the package which we're installing now.
+       * The `conffiles' data in the status file is ignored when a
+       * package isn't also listed in the file ownership database as
+       * having that file.  If several packages are listed as owning
+       * the file we pick one at random.
+       */
+      searchconff= 0;
+      for (packageslump= newconff->namenode->packages;
+           packageslump;
+           packageslump= packageslump->more) {
+        for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+          otherpkg= packageslump->pkgs[i];
+          debug(dbg_conffdetail,"process_archive conffile `%s' in package %s - conff ?",
+                newconff->namenode->name,otherpkg->name);
+          for (searchconff= otherpkg->installed.conffiles;
+               searchconff && strcmp(newconff->namenode->name,searchconff->name);
+               searchconff= searchconff->next)
+            debug(dbg_conffdetail,
+                  "process_archive conffile `%s' in package %s - conff ? not `%s'",
+                  newconff->namenode->name,otherpkg->name,searchconff->name);
+          if (searchconff) {
+            debug(dbg_conff,"process_archive conffile `%s' package=%s %s hash=%s",
+                  newconff->namenode->name,otherpkg->name,
+                  otherpkg == pkg ? "same" : "different!",
+                  searchconff->hash);
+            if (otherpkg == pkg) goto xit_conff_hashcopy_srch;
+          }
+        }
+      }
+    xit_conff_hashcopy_srch:
+      if (searchconff) {
+        newconff->namenode->oldhash= searchconff->hash;
+      } else {
+        debug(dbg_conff,"process_archive conffile `%s' no package, no hash",
+              newconff->namenode->name);
+      }
+      newconff->namenode->flags |= fnnf_new_conff;
+    }
+    if (ferror(conff)) ohshite("read error in %.250s",cidir);
+    pop_cleanup(ehflag_normaltidy); /* conff= fopen() */
+    if (fclose(conff)) ohshite("error closing %.250s",cidir);
+  } else {
+    if (errno != ENOENT) ohshite("error trying to open %.250s",cidir);
+  }
+
+  /* All the old conffiles are marked with a flag, so that we don't delete
+   * them if they seem to disappear completely.
+   */
+  oldconffsetflags(pkg->installed.conffiles);
+  if (conflictor) oldconffsetflags(conflictor->installed.conffiles);
+  
+  oldversionstatus= pkg->status;
+
+  assert(oldversionstatus <= stat_configfiles);
+  debug(dbg_general,"process_archive oldversionstatus=%s conflictor=%s",
+        statusstrings[oldversionstatus], conflictor ? conflictor->name : "<none>");
+  
+  if (oldversionstatus == stat_halfconfigured || oldversionstatus == stat_installed) {
+    pkg->eflag |= eflagf_reinstreq;
+    pkg->status= stat_halfconfigured;
+    modstatdb_note(pkg);
+    push_cleanup(cu_prermupgrade,~ehflag_normaltidy, 0,0, 1,(void*)pkg);
+    maintainer_script_alternative(pkg, PRERMFILE, "pre-removal", cidir, cidirrest,
+                                  "upgrade", "failed-upgrade");
+    pkg->status= stat_unpacked;
+    oldversionstatus= stat_unpacked;
+    modstatdb_note(pkg);
+  }
+
+  if (conflictor &&
+      (conflictor->status == stat_halfconfigured ||
+       conflictor->status == stat_installed)) {
+
+    for (deconpil= deconfigure; deconpil; deconpil= deconpil->next) {
+      printf("De-configuring %s, so that we can remove %s ...\n",
+             deconpil->pkg->name, conflictor->name);
+      deconpil->pkg->status= stat_halfconfigured;
+      modstatdb_note(deconpil->pkg);
+      /* This means that we *either* go and run postinst abort-deconfigure,
+       * *or* queue the package for later configure processing, depending
+       * on which error cleanup route gets taken.
+       */
+      push_cleanup(cu_prermdeconfigure,~ehflag_normaltidy,
+                   ok_prermdeconfigure,ehflag_normaltidy,
+                   3,(void*)deconpil->pkg,(void*)conflictor,(void*)pkg);
+      maintainer_script_installed(deconpil->pkg, PRERMFILE, "pre-removal",
+                                  "deconfigure", "in-favour", pkg->name,
+                                  versiondescribe(pkg->available.version,
+                                                  pkg->available.revision),
+                                  "removing", conflictor->name,
+                                  versiondescribe(conflictor->installed.version,
+                                                  conflictor->installed.revision),
+                                  (char*)0);
+    }
+    conflictor->status= stat_halfconfigured;
+    modstatdb_note(conflictor);
+    push_cleanup(cu_prerminfavour,~ehflag_normaltidy, 0,0,
+                 2,(void*)conflictor,(void*)pkg);
+    maintainer_script_installed(conflictor, PRERMFILE, "pre-removal",
+                                "remove", "in-favour", pkg->name,
+                                versiondescribe(pkg->available.version,
+                                                pkg->available.revision),
+                                (char*)0);
+    conflictor->status= stat_halfinstalled;
+    modstatdb_note(conflictor);
+  }
+
+  pkg->eflag |= eflagf_reinstreq;
+  pkg->status= stat_halfinstalled;
+  modstatdb_note(pkg);
+  if (oldversionstatus == stat_notinstalled) {
+    push_cleanup(cu_preinstverynew,~ehflag_normaltidy, 0,0,
+                 3,(void*)pkg,(void*)cidir,(void*)cidirrest);
+    maintainer_script_new(PREINSTFILE, "pre-installation", cidir, cidirrest,
+                          "install", (char*)0);
+  } else if (oldversionstatus == stat_configfiles) {
+    push_cleanup(cu_preinstnew,~ehflag_normaltidy, 0,0,
+                 3,(void*)pkg,(void*)cidir,(void*)cidirrest);
+    maintainer_script_new(PREINSTFILE, "pre-installation", cidir, cidirrest,
+                          "install", versiondescribe(pkg->installed.version,
+                                                     pkg->installed.revision),
+                          (char*)0);
+  } else {
+    push_cleanup(cu_preinstupgrade,~ehflag_normaltidy, 0,0,
+                 4,(void*)pkg,(void*)cidir,(void*)cidirrest,(void*)&oldversionstatus);
+    maintainer_script_new(PREINSTFILE, "pre-installation", cidir, cidirrest,
+                          "upgrade", versiondescribe(pkg->installed.version,
+                                                     pkg->installed.revision),
+                          (char*)0);
+    printf("Unpacking replacement %.250s ...\n",pkg->name);
+  }
+  
+  /*
+   * Now we unpack the archive, backing things up as we go.
+   * For each file, we check to see if it already exists.
+   * There are several possibilities:
+   * + We are trying to install a non-directory ...
+   *  - It doesn't exist.  In this case we simply extract it.
+   *  - It is a plain file, device, symlink, &c.  We do an `atomic
+   *    overwrite' using link() and rename(), but leave a backup copy.
+   *    Later, when we delete the backup, we remove it from any other
+   *    packages' lists.
+   * -  It is a directory.  In this case it depends on whether we're
+   *    trying to install a symlink or something else.
+   *   = If we're not trying to install a symlink we move the directory
+   *     aside and extract the node.  Later, when we recursively remove
+   *     the backed-up directory, we remove it from any other packages'
+   *     lists.
+   *   = If we are trying to install a symlink we do nothing - ie,
+   *     dpkg will never replace a directory tree with a symlink.  This
+   *     is to avoid embarrassing effects such as replacing a directory
+   *     tree with a link to a link to the original directory tree.
+   * + We are trying to install a directory ...
+   *  - It doesn't exist.  We create it with the appropriate modes.
+   *  - It exists as a directory or a symlink to one.  We do nothing.
+   *  - It is a plain file or a symlink (other than to a directory).
+   *    We move it aside and create the directory.  Later, when we
+   *    delete the backup, we remove it from any other packages' lists.
+   *
+   *                   Install non-dir   Install symlink   Install dir
+   *  Exists not               X               X                X
+   *  File/node/symlink       LXR             LXR              BXR
+   *  Directory               BXR              -                -
+   *
+   *    X: extract file/node/link/directory
+   *   LX: atomic overwrite leaving backup
+   *    B: ordinary backup
+   *    R: later remove from other packages' lists
+   *    -: do nothing
+   * 
+   * After we've done this we go through the remaining things in the
+   * lists of packages we're trying to remove (including the old
+   * version of the current package).  This happens in reverse order,
+   * so that we process files before the directories (or symlinks-to-
+   * directories) containing them.
+   * + If the thing is a conffile then we leave it alone for the purge
+   *   operation.
+   * + Otherwise, there are several possibilities too:
+   *  - The listed thing does not exist.  We ignore it.
+   *  - The listed thing is a directory or a symlink to a directory.
+   *    We delete it only if it isn't listed in any other package.
+   *  - The listed thing is not a directory or a symlink to one (ie,
+   *    it's a plain file, device, pipe, &c, or a symlink to one, or a
+   *    dangling symlink).  We delete it.
+   * The removed packages' list becomes empty (of course, the new
+   * version of the package we're installing will have a new list,
+   * which replaces the old version's list).
+   *
+   * If at any stage we remove a file from a package's list, and the
+   * package isn't one we're already processing, and the package's
+   * list becomes empty as a result, we `vanish' the package.  This
+   * means that we run its postrm with the `disappear' argument, and
+   * put the package in the `not-installed' state.  Its conffiles are
+   * ignored and forgotten about.
+   *
+   * NOTE THAT THE OLD POSTRM IS RUN AFTER THE NEW PREINST, since the
+   * files get replaced `as we go'.
+   */
+
+  m_pipe(p1);
+  push_cleanup(cu_closepipe,ehflag_bombout, 0,0, 1,(void*)&p1[0]);
+  c1= m_fork();
+  if (!c1) {
+    m_dup2(p1[1],1); close(p1[0]); close(p1[1]);
+    execlp(BACKEND, BACKEND, "--fsys-tarfile", filename, (char*)0);
+    ohshite("unable to exec " BACKEND " to get filesystem archive");
+  }
+  close(p1[1]);
+
+  newfileslist= 0; tc.newfilesp= &newfileslist;
+  push_cleanup(cu_fileslist,~0, 0,0, 1,(void*)&newfileslist);
+  tc.pkg= pkg;
+  tc.backendpipe= fdopen(p1[0],"r");
+  if (!tc.backendpipe) ohshite("unable to fdopen " BACKEND " extract pipe");
+  push_cleanup(cu_backendpipe,~ehflag_bombout, 0,0, 1,(void*)&tc.backendpipe);
+
+  r= TarExtractor((void*)&tc, &tf);
+  if (r) {
+    if (errno) {
+      ohshite("error reading " BACKEND " tar output");
+    } else if (feof(tc.backendpipe)) {
+      waitsubproc(c1,BACKEND " --fsys-tarfile (EOF)",1);
+      ohshit("unexpected EOF in filesystem tarfile - corrupted package archive");
+    } else {
+      ohshit("corrupted filesystem tarfile - corrupted package archive");
+    }
+  }
+  tmpf= tc.backendpipe;
+  tc.backendpipe= 0;
+  fclose(tmpf);
+  waitsubproc(c1,BACKEND " --fsys-tarfile",1);
+
+  if (oldversionstatus == stat_halfinstalled || oldversionstatus == stat_unpacked) {
+    /* Packages that were in `installed' and `postinstfailed' have been reduced
+     * to `unpacked' by now, by the running of the prerm script.
+     */
+    pkg->status= stat_halfinstalled;
+    modstatdb_note(pkg);
+    push_cleanup(cu_postrmupgrade,~ehflag_normaltidy, 0,0, 1,(void*)pkg);
+    maintainer_script_alternative(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+                                  "upgrade", "failed-upgrade");
+  }
+
+  /* If anything goes wrong while tidying up it's a bit late to do
+   * anything about it.  However, we don't install the new status
+   * info yet, so that a future dpkg installation will put everything
+   * right (we hope).
+   *
+   * If something does go wrong later the `conflictor' package will be
+   * left in the `removal_failed' state.  Removing or installing it
+   * will be impossible if it was required because of the conflict with
+   * the package we're installing now and (presumably) the dependency
+   * by other packages.  This means that the files it contains in
+   * common with this package will hang around until we successfully
+   * get this package installed, after which point we can trust the
+   * conflicting package's file list, which will have been updated to
+   * remove any files in this package.
+   */
+  push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+  
+  /* Now we delete all the files that were in the old version of
+   * the package only, except (old or new) conffiles, which we leave
+   * alone.
+   */
+  reversefilelist_init(&rlistit,pkg->clientdata->files);
+  while ((namenode= reversefilelist_next(&rlistit))) {
+    if ((namenode->flags & fnnf_old_conff) ||
+        (namenode->flags & fnnf_new_conff) ||
+        (namenode->flags & fnnf_new_inarchive))
+      continue;
+    if (isdirectoryinuse(namenode,pkg)) continue;
+    fnamevb.used= fnameidlu;
+    varbufaddstr(&fnamevb, namenodetouse(namenode,pkg)->name);
+    varbufaddc(&fnamevb,0);
+    if (!rmdir(fnamevb.buf)) continue;
+    if (errno == ENOENT || errno == ELOOP) continue;
+    if (errno == ENOTDIR) {
+      if (!unlink(fnamevb.buf)) continue;
+      if (errno == ENOTDIR) continue;
+    }
+    fprintf(stderr,
+            DPKG ": warning - unable to delete old file `%.250s': %s\n",
+            namenode->name, strerror(errno));
+  }
+
+  /* OK, now we can write the updated files-in-this package list,
+   * since we've done away (hopefully) with all the old junk.
+   */
+  write_filelist_except(pkg,newfileslist,0);
+
+  /* We also install the new maintainer scripts, and any other
+   * cruft that may have come along with the package.  First
+   * we go through the existing scripts replacing or removing
+   * them as appropriate; then we go through the new scripts
+   * (any that are left) and install them.
+   */
+  debug(dbg_general, "process_archive updating info directory");
+  varbufreset(&infofnvb);
+  varbufaddstr(&infofnvb,admindir);
+  varbufaddstr(&infofnvb,"/" INFODIR "/");
+  infodirlen= infofnvb.used;
+  varbufaddc(&infofnvb,0);
+  dsd= opendir(infofnvb.buf);
+  if (!dsd) ohshite("cannot read info directory");
+  push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+  while ((de= readdir(dsd)) != 0) {
+    debug(dbg_veryverbose, "process_archive info file `%s'", de->d_name);
+    if (de->d_name[0] == '.') continue; /* ignore dotfiles, including `.' and `..' */
+    p= strrchr(de->d_name,'.'); if (!p) continue; /* ignore anything odd */
+    if (strlen(pkg->name) != p-de->d_name ||
+        strncmp(de->d_name,pkg->name,p-de->d_name)) continue;
+    debug(dbg_stupidlyverbose, "process_archive info this pkg");
+    /* Right do we have one ? */
+    p++; /* skip past the full stop */
+    if (!strcmp(p,LISTFILE)) continue; /* We do the list separately */
+    if (strlen(p) > MAXCONTROLFILENAME)
+      ohshit("old version of package has overly-long info file name starting `%.250s'",
+             de->d_name);
+    infofnvb.used= infodirlen;
+    varbufaddstr(&infofnvb,de->d_name);
+    varbufaddc(&infofnvb,0);
+    strcpy(cidirrest,p);
+    if (!rename(cidir,infofnvb.buf)) {
+      debug(dbg_scripts, "process_archive info installed %s as %s",
+            cidir, infofnvb.buf);
+    } else if (errno == ENOENT) {
+      /* Right, no new version. */
+      if (unlink(infofnvb.buf))
+        ohshite("unable to remove obsolete info file `%.250s'",infofnvb.buf);
+      debug(dbg_scripts, "process_archive info unlinked %s",infofnvb.buf);
+    } else {
+      ohshite("unable to install (supposed) new info file `%.250s'",cidir);
+    }
+  }
+  pop_cleanup(ehflag_normaltidy); /* closedir */
+  
+  *cidirrest= 0; /* the directory itself */
+  dsd= opendir(cidir);
+  if (!dsd) ohshite("unable to open temp control directory");
+  push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+  while ((de= readdir(dsd))) {
+    if (strchr(de->d_name,'.')) {
+      debug(dbg_scripts,"process_archive tmp.ci script/file `%s' contains dot",
+            de->d_name);
+      continue;
+    }
+    if (strlen(de->d_name) > MAXCONTROLFILENAME)
+      ohshit("package contains overly-long control info file name (starting `%.50s')",
+             de->d_name);
+    strcpy(cidirrest,de->d_name);
+    /* First we check it's not a directory. */
+    if (!rmdir(cidir))
+      ohshit("package control info contained directory `%.250s'",cidir);
+    else if (errno != ENOTDIR)
+      ohshite("package control info rmdir of `%.250s' didn't say not a dir",de->d_name);
+    if (!strcmp(de->d_name,CONTROLFILE)) {
+      debug(dbg_scripts,"process_archive tmp.ci script/file `%s' is control",cidir);
+      continue; /* ignore the control file */
+    }
+    if (!strcmp(de->d_name,LISTFILE)) {
+      fprintf(stderr, DPKG ": warning - package %s"
+              " contained list as info file", pkg->name);
+      continue;
+    }
+    /* Right, install it */
+    newinfofilename= pkgadminfile(pkg,de->d_name);
+    if (rename(cidir,newinfofilename))
+      ohshite("unable to install new info file `%.250s' as `%.250s'",
+              cidir,newinfofilename);
+    debug(dbg_scripts,"process_archive tmp.ci script/file `%s' installed as `%s'",
+          cidir, newinfofilename);
+  }
+  pop_cleanup(ehflag_normaltidy); /* closedir */
+
+  /* Update the status database.
+   * This involves copying each field across from the `available'
+   * to the `installed' half of the pkg structure.
+   * For some of the fields we have to do a complicated construction
+   * operation; for others we can just copy the value.
+   * We tackle the fields in the order they appear, so that
+   * we don't miss any out :-).
+   * At least we don't have to copy any strings that are referred
+   * to, because these are never modified and never freed.
+   */
+
+  /* The dependencies are the most difficult.  We have to build
+   * a whole new forward dependency tree.  At least the reverse
+   * links (linking our deppossi's into the reverse chains)
+   * can be done by copy_dependency_links.
+   */
+  newdeplist= 0; newdeplistlastp= &newdeplist;
+  for (dep= pkg->available.depends; dep; dep= dep->next) {
+    newdep= nfmalloc(sizeof(struct dependency));
+    newdep->up= pkg;
+    newdep->next= 0;
+    newdep->list= 0; newpossilastp= &newdep->list;
+    for (possi= dep->list; possi; possi= possi->next) {
+      newpossi= nfmalloc(sizeof(struct deppossi));
+      newpossi->up= newdep;
+      newpossi->ed= possi->ed;
+      newpossi->next= 0; newpossi->nextrev= newpossi->backrev= 0;
+      newpossi->verrel= possi->verrel;
+      if (possi->verrel != dvr_none) {
+        newpossi->version= possi->version;
+        newpossi->revision= possi->revision;
+      }
+      newpossi->cyclebreak= 0;
+      *newpossilastp= newpossi;
+      newpossilastp= &newpossi->next;
+    }
+    newdep->type= dep->type;
+    *newdeplistlastp= newdep;
+    newdeplistlastp= &newdep->next;
+  }
+  /* Right, now we've replicated the forward tree, we
+   * get copy_dependency_links to remove all the old dependency
+   * structures from the reverse links and add the new dependency
+   * structures in instead.  It also copies the new dependency
+   * structure pointer for this package into the right field.
+   */
+  copy_dependency_links(pkg,&pkg->installed.depends,newdeplist,0);
+
+  /* The `depended' pointer in the structure doesn't represent anything
+   * that is actually specified by this package - it's there so we
+   * can find out what other packages refer to this one.  So,
+   * we don't copy it.  We go straight on to copy the text fields.
+   */
+  pkg->installed.essential= pkg->available.essential;
+  pkg->installed.description= pkg->available.description;
+  pkg->installed.maintainer= pkg->available.maintainer;
+  pkg->installed.source= pkg->available.source;
+  pkg->installed.architecture= 0; /* This is irrelevant in the status file. */
+  pkg->installed.version= pkg->available.version;
+  pkg->installed.revision= pkg->available.revision;
+
+  /* We have to generate our own conffiles structure. */
+  pkg->installed.conffiles= 0; iconffileslastp= &pkg->installed.conffiles;
+  for (cfile= newconffiles; cfile; cfile= cfile->next) {
+    newiconff= nfmalloc(sizeof(struct conffile));
+    newiconff->next= 0;
+    newiconff->name= nfstrsave(cfile->namenode->name);
+    newiconff->hash= nfstrsave(cfile->namenode->oldhash);
+    *iconffileslastp= newiconff;
+    iconffileslastp= &newiconff->next;
+  }
+
+  /* We can just copy the arbitrary fields list, because it is
+   * never even rearragned.  Phew !
+   */
+  pkg->installed.arbs= pkg->available.arbs;
+
+  /* Check for disappearing packages:
+   * We go through all the packages on the system looking for ones
+   * whose files are entirely part of the one we've just unpacked
+   * (and which actually *have* some files!).
+   *
+   * Any that we find are removed - we run the postrm with `disappear'
+   * as an argument, and remove their info/... files and status info.
+   * Conffiles are ignored (the new package had better do something
+   * with them !).
+   */
+  it= iterpkgstart();
+  while ((otherpkg= iterpkgnext(it)) != 0) {
+    ensure_package_clientdata(otherpkg);
+    if (otherpkg == pkg ||
+        otherpkg == conflictor ||
+        otherpkg->status == stat_notinstalled ||
+        otherpkg->status == stat_configfiles ||
+        !otherpkg->clientdata->files) continue;
+    debug(dbg_veryverbose, "process_archive checking disappearance %s",otherpkg->name);
+    assert(otherpkg->clientdata->istobe == itb_normal ||
+           otherpkg->clientdata->istobe == itb_deconfigure);
+    for (cfile= otherpkg->clientdata->files;
+         cfile && !strcmp(cfile->namenode->name,"/.");
+         cfile= cfile->next);
+    if (!cfile) {
+      debug(dbg_stupidlyverbose, "process_archive no non-root, no disappear");
+      continue;
+    }
+    for (cfile= otherpkg->clientdata->files;
+         cfile;
+         cfile= cfile->next) {
+      if (!(cfile->namenode->flags & fnnf_new_inarchive)) break;
+      if (cfile->namenode->divert && cfile->namenode->divert->useinstead) {
+        /* If the file is a contended one and it's overridden by either the package
+         * we're considering disappearing or the package we're installing then
+         * they're not actually the same file, so we can't disappear the package.
+         */
+        divpkg= cfile->namenode->divert->pkg;
+        if (divpkg == pkg || divpkg == otherpkg) break;
+      }
+    }
+    if (cfile) {
+      debug(dbg_stupidlyverbose, "process_archive saved by `%s'",cfile->namenode->name);
+      continue;
+    }
+
+    /* So dependency things will give right answers ... */
+    otherpkg->clientdata->istobe= itb_remove; 
+    debug(dbg_veryverbose, "process_archive disappear checking dependencies");
+    for (pdep= otherpkg->installed.depended;
+         pdep;
+         pdep= pdep->nextrev) {
+      if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends &&
+          pdep->up->type != dep_recommends) continue;
+      if (depisok(pdep->up, &depprobwhy, 0,0)) continue;
+      varbufaddc(&depprobwhy,0);
+      debug(dbg_veryverbose,"process_archive cannot disappear: %s",depprobwhy.buf);
+      break;
+    }
+    if (!pdep) {
+      /* If we haven't found a reason not to yet, let's look some more. */
+      for (providecheck= otherpkg->installed.depends;
+           providecheck;
+           providecheck= providecheck->next) {
+        if (providecheck->type != dep_provides) continue;
+        for (pdep= providecheck->list->ed->installed.depended;
+             pdep;
+             pdep= pdep->nextrev) {
+          if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends &&
+              pdep->up->type != dep_recommends)
+            continue;
+          if (depisok(pdep->up, &depprobwhy, 0,0)) continue;
+          varbufaddc(&depprobwhy,0);
+          debug(dbg_veryverbose,"process_archive cannot disappear (provides %s): %s",
+                providecheck->list->ed->name, depprobwhy.buf);
+          goto break_from_both_loops_at_once;
+        }
+      }
+    break_from_both_loops_at_once:;
+    }
+    otherpkg->clientdata->istobe= itb_normal;
+    if (pdep) continue;
+
+    printf("(Noting disappearance of %s, which has been completely replaced.)\n",
+           otherpkg->name);
+    debug(dbg_general, "process_archive disappearing %s",otherpkg->name);
+    /* No, we're disappearing it.  This is the wrong time to go and
+     * run maintainer scripts and things, as we can't back out.  But
+     * what can we do ?  It has to be run this late.
+     */
+    maintainer_script_installed(otherpkg, POSTRMFILE,
+                                "post-removal script (for disappearance)",
+                                "disappear", pkg->name, 
+                                versiondescribe(pkg->available.version,
+                                                pkg->available.revision),
+                                (char*)0);
+
+    /* OK, now we delete all the stuff in the `info' directory .. */
+    varbufreset(&fnvb);
+    varbufaddstr(&fnvb,admindir);
+    varbufaddstr(&fnvb,"/" INFODIR);
+    infodirbaseused= fnvb.used;
+    varbufaddc(&fnvb,0);
+    dsd= opendir(fnvb.buf); if (!dsd) ohshite("cannot read info directory");
+    push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+
+    debug(dbg_general, "process_archive disappear cleaning info directory");
+      
+    while ((de= readdir(dsd)) != 0) {
+      debug(dbg_veryverbose, "process_archive info file `%s'", de->d_name);
+      if (de->d_name[0] == '.') continue;
+      p= strrchr(de->d_name,'.'); if (!p) continue;
+      if (strlen(otherpkg->name) != p-de->d_name ||
+          strncmp(de->d_name,otherpkg->name,p-de->d_name)) continue;
+      debug(dbg_stupidlyverbose, "process_archive info this pkg");
+      fnvb.used= infodirbaseused;
+      varbufaddstr(&fnvb,de->d_name);
+      varbufaddc(&fnvb,0);
+      if (unlink(fnvb.buf))
+        ohshite("unable to delete disappearing control info file `%.250s'",fnvb.buf);
+      debug(dbg_scripts, "process_archive info unlinked %s",fnvb.buf);
+    }
+    pop_cleanup(ehflag_normaltidy); /* closedir */
+    
+    otherpkg->status= stat_notinstalled;
+    otherpkg->want= want_purge;
+    otherpkg->eflag= eflagv_ok;
+
+    otherpkg->installed.depends= 0;
+    otherpkg->installed.essential= 0;
+    otherpkg->installed.description= otherpkg->installed.maintainer=
+      otherpkg->installed.version= otherpkg->installed.revision= 0;
+    otherpkg->installed.arbs= 0;
+    otherpkg->clientdata->fileslistvalid= 0;
+
+    modstatdb_note(otherpkg);
+
+  } /* while (otherpkg= ... */
+  iterpkgend(it);
+  
+  /* Delete files from any other packages' lists.
+   * We have to do this before we claim this package is in any
+   * sane kind of state, as otherwise we might delete by mistake
+   * a file that we overwrote, when we remove the package which
+   * had the version we overwrote.  To prevent this we make
+   * sure that we don't claim this package is OK until we
+   * have claimed `ownership' of all its files.
+   */
+  for (cfile= newfileslist; cfile; cfile= cfile->next) {
+    if (!(cfile->namenode->flags & fnnf_elide_other_lists)) continue;
+    if (cfile->namenode->divert && cfile->namenode->divert->useinstead) {
+      divpkg= cfile->namenode->divert->pkg;
+      if (divpkg == pkg) {
+        debug(dbg_eachfile,
+              "process_archive not overwriting any `%s' (overriding, `%s')",
+              cfile->namenode->name, cfile->namenode->divert->useinstead->name);
+        continue;
+      } else {
+        debug(dbg_eachfile,
+              "process_archive looking for overwriting `%s' (overridden by %s)",
+              cfile->namenode->name, divpkg->name);
+      }        
+    } else {
+      divpkg= 0;
+      debug(dbg_eachfile, "process_archive looking for overwriting `%s'",
+            cfile->namenode->name);
+    }
+    for (packageslump= cfile->namenode->packages;
+         packageslump;
+         packageslump= packageslump->more) {
+      for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+        otherpkg= packageslump->pkgs[i];
+        debug(dbg_eachfiledetail, "process_archive ... found in %s\n",otherpkg->name);
+        /* If !fileslistvalid then it's one of the disappeared packages above
+         * and we don't bother with it here, clearly.
+         */
+        if (otherpkg == pkg || !otherpkg->clientdata->fileslistvalid) continue;
+        if (otherpkg == divpkg) {
+          debug(dbg_eachfiledetail, "process_archive ... diverted, skipping\n");
+          continue;
+        }
+
+        /* Found one.  We delete remove the list entry for this file,
+         * (and any others in the same package) and then mark the package
+         * as requiring a reread.
+         */
+        write_filelist_except(otherpkg, otherpkg->clientdata->files, 1);
+        ensure_package_clientdata(otherpkg);
+        debug(dbg_veryverbose, "process_archive overwrote from %s",otherpkg->name);
+      }
+    }
+  }
+
+  /* Right, the package we've unpacked is now in a reasonable state.
+   * The only thing that we have left to do with it is remove
+   * backup files, and we can leave the user to fix that if and when
+   * it happens (we leave the reinstall required flag, of course).
+   */
+  pkg->status= stat_unpacked;
+  modstatdb_note(pkg);
+  
+  /* Now we delete all the backup files that we made when
+   * extracting the archive - except for files listed as conffiles
+   * in the new package.
+   * This time we count it as an error if something goes wrong.
+   *
+   * Note that we don't ever delete things that were in the old
+   * package as a conffile and don't appear at all in the new.
+   */
+  for (cfile= newfileslist; cfile; cfile= cfile->next) {
+    if (cfile->namenode->flags & fnnf_new_conff) continue;
+    fnametmpvb.used= fnameidlu;
+    varbufaddstr(&fnametmpvb,namenodetouse(cfile->namenode,pkg)->name);
+    varbufaddstr(&fnametmpvb,DPKGTEMPEXT);
+    varbufaddc(&fnametmpvb,0);
+    ensure_pathname_nonexisting(fnametmpvb.buf);
+  }
+
+  /* OK, we're now fully done with the main package.
+   * This is quite a nice state, so we don't unwind past here.
+   */
+  pkg->eflag= eflagv_ok;
+  modstatdb_note(pkg);
+  push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+  /* Only the removal of the conflictor left to do.
+   * The files list for the conflictor is still a little inconsistent in-core,
+   * as we have not yet updated the filename->packages mappings; however,
+   * the package->filenames mapping is 
+   */
+  if (conflictor) {
+    /* We need to have the most up-to-date info about which files are what ... */
+    ensure_allinstfiles_available();
+    removal_bulk(conflictor);
+  }
+
+  if (cipaction->arg == act_install) add_to_queue(pkg);
+}
diff --git a/main/remove.c b/main/remove.c
new file mode 100644 (file)
index 0000000..94199da
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * dpkg - main program for package management
+ * remove.c - functionality for removing packages
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "filesdb.h"
+#include "main.h"
+
+void deferred_remove(struct pkginfo *pkg) {
+  struct varbuf raemsgs;
+  int rok, before, ok;
+  struct deppossi *dep;
+  struct pkginfo *depender;
+
+  debug(dbg_general,"deferred_remove package %s",pkg->name);
+  
+  if (pkg->status == stat_notinstalled) {
+    fprintf(stderr, DPKG
+            " - warning: ignoring request to remove %.250s which isn't installed.\n",
+            pkg->name);
+    pkg->clientdata->istobe= itb_normal;
+    return;
+  } else if (!f_pending &&
+             pkg->status == stat_configfiles &&
+             cipaction->arg != act_purge) {
+    fprintf(stderr, DPKG
+            " - warning: ignoring request to remove %.250s, only the config\n"
+            " files of which are on the system.  Use --purge to remove them too.\n",
+            pkg->name);
+    pkg->clientdata->istobe= itb_normal;
+    return;
+  }
+
+  assert(pkg->installed.valid);
+  if (pkg->installed.essential)
+    forcibleerr(fc_removeessential, "This is an essential package -"
+                " it should not be removed.");
+
+  if (!f_pending)
+    pkg->want= (cipaction->arg == act_purge) ? want_purge : want_deinstall;
+  if (!f_noact) modstatdb_note(pkg);
+
+  debug(dbg_general,"checking dependencies for remove `%s'",pkg->name);
+  varbufinit(&raemsgs);
+  rok= 2;
+  for (dep= pkg->installed.depended; dep; dep= dep->nextrev) {
+    if (dep->up->type != dep_depends && dep->up->type != dep_predepends) continue;
+    depender= dep->up->up;
+    debug(dbg_depcon,"checking depending package `%s'",depender->name);
+    if (depender->status != stat_installed) continue;
+    if (ignore_depends(depender)) {
+      debug(dbg_depcon,"ignoring depending package `%s'\n",depender->name);
+      continue;
+    }
+    if (dependtry > 1) { if (findbreakcycle(pkg,0)) sincenothing= 0; }
+    before= raemsgs.used;
+    ok= dependencies_ok(depender,pkg,&raemsgs);
+    if (ok == 0 && depender->clientdata->istobe == itb_remove) ok= 1;
+    if (ok == 1) raemsgs.used= before; /* Don't burble about reasons for deferral */
+    if (ok < rok) rok= ok;
+  }
+  if (rok == 1) {
+    varbuffree(&raemsgs);
+    pkg->clientdata->istobe= itb_remove;
+    add_to_queue(pkg);
+    return;
+  } else if (rok == 0) {
+    sincenothing= 0;
+    varbufaddc(&raemsgs,0);
+    fprintf(stderr,
+            DPKG ": dependency problems prevent removal of %s:\n%s",
+            pkg->name, raemsgs.buf);
+    ohshit("dependency problems - not removing");
+  } else if (raemsgs.used) {
+    varbufaddc(&raemsgs,0);
+    fprintf(stderr,
+            DPKG ": %s: dependency problems, but removing anyway as you request:\n%s",
+            pkg->name, raemsgs.buf);
+  }
+  varbuffree(&raemsgs);
+  sincenothing= 0;
+
+  if (pkg->eflag & eflagf_reinstreq)
+    forcibleerr(fc_removereinstreq,
+                "Package is in a very bad inconsistent state - you should\n"
+                " reinstall it before attempting a removal.");
+
+  ensure_allinstfiles_available();
+  filesdbinit();
+
+  if (f_noact) {
+    printf("Would remove or purge %s ...\n",pkg->name);
+    pkg->status= stat_notinstalled;
+    pkg->clientdata->istobe= itb_normal;
+    return;
+  }
+
+  oldconffsetflags(pkg->installed.conffiles);
+    
+  printf("Removing %s ...\n",pkg->name);
+  if (pkg->status == stat_halfconfigured || pkg->status == stat_installed) {
+
+    if (pkg->status == stat_installed || pkg->status == stat_halfconfigured) {
+      pkg->status= stat_halfconfigured;
+      modstatdb_note(pkg);
+      push_cleanup(cu_prermremove,~ehflag_normaltidy, 0,0, 1,(void*)pkg);
+      maintainer_script_installed(pkg, PRERMFILE, "pre-removal",
+                                  "remove", (char*)0);
+    }
+
+    pkg->status= stat_unpacked; /* Will turn into halfinstalled soon ... */
+  }
+
+  removal_bulk(pkg);
+}
+
+static void push_leftover(struct fileinlist **leftoverp,
+                          struct filenamenode *namenode) {
+  struct fileinlist *newentry;
+  newentry= nfmalloc(sizeof(struct fileinlist));
+  newentry->next= *leftoverp;
+  newentry->namenode= namenode;
+  *leftoverp= newentry;
+}
+
+void removal_bulk(struct pkginfo *pkg) {
+  /* This is used both by deferred_remove in this file, and at
+   * the end of process_archive in archives.c if it needs to finish
+   * removing a conflicting package.
+   */
+  static const char *const removeconffexts[]= { REMOVECONFFEXTS, 0 };
+
+  static struct varbuf fnvb, removevb;
+  
+  int before, r, foundpostrm, removevbbase;
+  int infodirbaseused, conffnameused, conffbasenamelen, pkgnameused;
+  char *conffbasename;
+  struct reversefilelistiter rlistit;
+  struct conffile *conff, **lconffp;
+  struct fileinlist *searchfile, *leftover;
+  struct stat stab;
+  DIR *dsd;
+  struct dirent *de;
+  char *p;
+  const char *const *ext;
+  const char *postrmfilename;
+  struct filenamenode *namenode;
+
+  debug(dbg_general,"removal_bulk package %s",pkg->name);
+  
+  if (pkg->status == stat_halfinstalled || pkg->status == stat_unpacked) {
+    pkg->status= stat_halfinstalled;
+    modstatdb_note(pkg);
+    push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+    reversefilelist_init(&rlistit,pkg->clientdata->files);
+    leftover= 0;
+    while ((namenode= reversefilelist_next(&rlistit))) {
+      debug(dbg_eachfile, "removal_bulk `%s' flags=%o",
+            namenode->name, namenode->flags);
+      if (namenode->flags & fnnf_old_conff) {
+        push_leftover(&leftover,namenode);
+        continue;
+      }
+      varbufreset(&fnvb);
+      varbufaddstr(&fnvb,instdir);
+      varbufaddstr(&fnvb,namenodetouse(namenode,pkg)->name);
+      before= fnvb.used;
+      
+      varbufaddstr(&fnvb,DPKGTEMPEXT);
+      varbufaddc(&fnvb,0);
+      debug(dbg_eachfiledetail, "removal_bulk cleaning temp `%s'", fnvb.buf);
+      
+      ensure_pathname_nonexisting(fnvb.buf);
+      
+      fnvb.used= before;
+      varbufaddstr(&fnvb,DPKGNEWEXT);
+      varbufaddc(&fnvb,0);
+      debug(dbg_eachfiledetail, "removal_bulk cleaning new `%s'", fnvb.buf);
+      ensure_pathname_nonexisting(fnvb.buf);
+      
+      fnvb.used= before;
+      varbufaddc(&fnvb,0);
+      if (!stat(fnvb.buf,&stab) && S_ISDIR(stab.st_mode)) {
+        debug(dbg_eachfiledetail, "removal_bulk is a directory");
+        /* Only delete a directory or a link to one if we're the only
+         * package which uses it.  Other files should only be listed
+         * in this package (but we don't check).
+         */
+        if (isdirectoryinuse(namenode,pkg)) continue;
+      }
+      debug(dbg_eachfiledetail, "removal_bulk removing `%s'", fnvb.buf);
+      if (!rmdir(fnvb.buf) || errno == ENOENT || errno == ELOOP) continue;
+      if (errno == ENOTEMPTY) {
+        fprintf(stderr, DPKG
+                " - warning: while removing %.250s, directory `%.250s' not empty "
+                "so not removed.\n",
+                pkg->name, namenode->name);
+        push_leftover(&leftover,namenode);
+        continue;
+      } else if (errno == EPERM) {
+        fprintf(stderr, DPKG " - warning: while removing %.250s,"
+                " unable to remove directory `%.250s':"
+                " Operation not permitted - directory may be a mount point ?\n",
+                pkg->name, namenode->name);
+        push_leftover(&leftover,namenode);
+        continue;
+      }
+      if (errno != ENOTDIR) ohshite("cannot remove `%.250s'",fnvb.buf);
+      debug(dbg_eachfiledetail, "removal_bulk unlinking `%s'", fnvb.buf);
+      if (unlink(fnvb.buf)) ohshite("cannot remove file `%.250s'",fnvb.buf);
+    }
+    write_filelist_except(pkg,leftover,0);
+    maintainer_script_installed(pkg, POSTRMFILE, "post-removal",
+                                "remove", (char*)0);
+    varbufreset(&fnvb);
+    varbufaddstr(&fnvb,admindir);
+    varbufaddstr(&fnvb,"/" INFODIR);
+    infodirbaseused= fnvb.used;
+    varbufaddc(&fnvb,0);
+    dsd= opendir(fnvb.buf); if (!dsd) ohshite("cannot read info directory");
+    push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+    foundpostrm= 0;
+
+    debug(dbg_general, "removal_bulk cleaning info directory");
+
+    while ((de= readdir(dsd)) != 0) {
+      debug(dbg_veryverbose, "removal_bulk info file `%s'", de->d_name);
+      if (de->d_name[0] == '.') continue;
+      p= strrchr(de->d_name,'.'); if (!p) continue;
+      if (strlen(pkg->name) != p-de->d_name ||
+          strncmp(de->d_name,pkg->name,p-de->d_name)) continue;
+      debug(dbg_stupidlyverbose, "removal_bulk info this pkg");
+      /* We need the postrm and list files for --purge. */
+      if (!strcmp(p+1,LISTFILE)) continue;
+      if (!strcmp(p+1,POSTRMFILE)) { foundpostrm=1; continue; }
+      debug(dbg_stupidlyverbose, "removal_bulk info not postrm or list");
+      fnvb.used= infodirbaseused;
+      varbufaddstr(&fnvb,de->d_name);
+      varbufaddc(&fnvb,0);
+      if (unlink(fnvb.buf))
+        ohshite("unable to delete control info file `%.250s'",fnvb.buf);
+      debug(dbg_scripts, "removal_bulk info unlinked %s",fnvb.buf);
+    }
+    pop_cleanup(ehflag_normaltidy); /* closedir */
+    
+    pkg->status= stat_configfiles;
+    modstatdb_note(pkg);
+    push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+  } else {
+
+    postrmfilename= pkgadminfile(pkg,POSTRMFILE);
+    if (!lstat(postrmfilename,&stab)) foundpostrm= 1;
+    else if (errno == ENOENT) foundpostrm= 0;
+    else ohshite("unable to check existence of `%.250s'",postrmfilename);
+
+  }
+  
+  debug(dbg_general, "removal_bulk purging? foundpostrm=%d",foundpostrm);
+  
+  if (!foundpostrm && !pkg->installed.conffiles) {
+    /* If there are no config files and no postrm script then we
+     * go straight into `purge'.
+     */
+    debug(dbg_general, "removal_bulk no postrm, no conffiles, purging");
+    pkg->want= want_purge;
+
+  } else if (pkg->want == want_purge) {
+
+    printf("Purging configuration files for %s ...\n",pkg->name);
+    ensure_packagefiles_available(pkg); /* We may have modified this above. */
+
+    /* We're about to remove the configuration, so remove the note
+     * about which version it was ...
+     */
+    pkg->configversion= pkg->configrevision= 0;
+    modstatdb_note(pkg);
+    
+    /* Remove from our list any conffiles that aren't ours any more or
+     * are involved in diversions, except if we are the package doing the
+     * diverting.
+     */
+    for (lconffp= &pkg->installed.conffiles;
+         (conff= *lconffp) != 0;
+         lconffp= &conff->next) {
+      for (searchfile= pkg->clientdata->files;
+           searchfile && strcmp(searchfile->namenode->name,conff->name);
+           searchfile= searchfile->next);
+      if (!searchfile) {
+        debug(dbg_conff,"removal_bulk conffile not ours any more `%s'",conff->name);
+        *lconffp= conff->next;
+      } else if (searchfile->namenode->divert &&
+                 (searchfile->namenode->divert->camefrom ||
+                  (searchfile->namenode->divert->useinstead &&
+                   searchfile->namenode->divert->pkg != pkg))) {
+        debug(dbg_conff,"removal_bulk conffile `%s' ignored due to diversion\n",
+              conff->name);
+        *lconffp= conff->next;
+      } else {
+        debug(dbg_conffdetail,"removal_bulk set to new conffile `%s'",conff->name);
+        conff->hash= (char*)NEWCONFFILEFLAG; /* yes, cast away const */
+      }
+    }
+    modstatdb_note(pkg);
+    
+    for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
+      varbufreset(&fnvb);
+      r= conffderef(pkg, &fnvb, conff->name);
+      debug(dbg_conffdetail, "removal_bulk conffile `%s' (= `%s')",
+            conff->name, r == -1 ? "<r==-1>" : fnvb.buf);
+      if (r == -1) continue;
+      conffnameused= fnvb.used-1;
+      if (unlink(fnvb.buf) && errno != ENOENT && errno != ENOTDIR)
+        ohshite("cannot remove old config file `%.250s' (= `%.250s')",
+                conff->name, fnvb.buf);
+      p= strrchr(fnvb.buf,'/'); if (!p) continue;
+      *p= 0;
+      varbufreset(&removevb);
+      varbufaddstr(&removevb,fnvb.buf);
+      varbufaddc(&removevb,'/');
+      removevbbase= removevb.used;
+      varbufaddc(&removevb,0);
+      dsd= opendir(removevb.buf);
+      if (!dsd) {
+        int e=errno;
+        debug(dbg_conffdetail, "removal_bulk conffile no dsd %s %s",
+              fnvb.buf, strerror(e)); errno= e;
+        if (errno == ENOENT || errno == ENOTDIR) continue;
+        ohshite("cannot read config file dir `%.250s' (from `%.250s')",
+                fnvb.buf, conff->name);
+      }
+      debug(dbg_conffdetail, "removal_bulk conffile cleaning dsd %s", fnvb.buf);
+      push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
+      *p= '/';
+      conffbasenamelen= strlen(++p);
+      conffbasename= fnvb.buf+conffnameused-conffbasenamelen;
+      while ((de= readdir(dsd)) != 0) {
+        debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry=`%s'"
+              " conffbasename=`%s' conffnameused=%d conffbasenamelen=%d",
+              de->d_name, conffbasename, conffnameused, conffbasenamelen);
+        if (!strncmp(de->d_name,conffbasename,conffbasenamelen)) {
+          debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry starts right");
+          for (ext= removeconffexts; *ext; ext++)
+            if (!strcmp(*ext,de->d_name+conffbasenamelen)) goto yes_remove;
+          p= de->d_name+conffbasenamelen;
+          if (*p++ == '~') {
+            while (*p && isdigit(*p)) p++;
+            if (*p == '~' && !*++p) goto yes_remove;
+          }
+        }
+        debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry starts wrong");
+        if (de->d_name[0] == '#' &&
+            !strncmp(de->d_name+1,conffbasename,conffbasenamelen) &&
+            !strcmp(de->d_name+1+conffbasenamelen,"#"))
+          goto yes_remove;
+        debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry not it");
+        continue;
+      yes_remove:
+        removevb.used= removevbbase;
+        varbufaddstr(&removevb,de->d_name); varbufaddc(&removevb,0);
+        debug(dbg_conffdetail, "removal_bulk conffile dsd entry removing `%s'",
+              removevb.buf);
+        if (unlink(removevb.buf) && errno != ENOENT && errno != ENOTDIR)
+          ohshite("cannot remove old backup config file `%.250s' (of `%.250s')",
+                  removevb.buf, conff->name);
+      }
+      pop_cleanup(ehflag_normaltidy); /* closedir */
+    
+    }
+    
+    pkg->installed.conffiles= 0;
+    modstatdb_note(pkg);
+        
+    maintainer_script_installed(pkg, POSTRMFILE, "post-removal",
+                                "purge", (char*)0);
+
+    /* fixme: retry empty directories */
+
+  }
+
+  if (pkg->want == want_purge) {
+
+    /* ie, either of the two branches above. */
+    varbufreset(&fnvb);
+    varbufaddstr(&fnvb,admindir);
+    varbufaddstr(&fnvb,"/" INFODIR);
+    varbufaddstr(&fnvb,pkg->name);
+    pkgnameused= fnvb.used;
+    
+    varbufaddstr(&fnvb,"." LISTFILE);
+    varbufaddc(&fnvb,0);
+    debug(dbg_general, "removal_bulk purge done, removing list `%s'",fnvb.buf);
+    if (unlink(fnvb.buf) && errno != ENOENT) ohshite("cannot remove old files list");
+    
+    fnvb.used= pkgnameused;
+    varbufaddstr(&fnvb,"." POSTRMFILE);
+    varbufaddc(&fnvb,0);
+    debug(dbg_general, "removal_bulk purge done, removing postrm `%s'",fnvb.buf);
+    if (unlink(fnvb.buf) && errno != ENOENT) ohshite("can't remove old postrm script");
+
+    pkg->status= stat_notinstalled;
+
+    /* This will mess up reverse links, but if we follow them
+     * we won't go back because pkg->status is stat_notinstalled.
+     */
+    pkg->installed.depends= 0;
+    pkg->installed.essential= 0;
+    pkg->installed.description= pkg->installed.maintainer=
+      pkg->installed.version= pkg->installed.revision= 0;
+    pkg->installed.arbs= 0;
+  }
+      
+  pkg->eflag= eflagv_ok;
+  modstatdb_note(pkg);
+
+  debug(dbg_general, "removal done");
+}
+
diff --git a/main/update.c b/main/update.c
new file mode 100644 (file)
index 0000000..3193937
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * dpkg - main program for package management
+ * update.c - options which update the `available' database
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "myopt.h"
+
+#include "main.h"
+
+void availablefrompackages(const char *const *argv, int replace) {
+  const char *sourcefile= argv[0];
+  int count;
+  static struct varbuf vb;
+  
+  if (!sourcefile || argv[1])
+    badusage("--%s needs exactly one Packages file argument", cipaction->olong);
+  
+  if (!f_noact) {
+    if (access(admindir,W_OK)) {
+      if (errno != EACCES)
+        ohshite("unable to access dpkg status area for bulk available update");
+      else
+        ohshit("bulk available update requires write access to dpkg status area");
+    }
+    lockdatabase(admindir);
+  }
+  
+  if (replace) {
+    printf("Replacing available packages info, using %s.\n",sourcefile);
+  } else {
+    printf("Updating available packages info, using %s.\n",sourcefile);
+  }
+
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" AVAILFILE);
+  varbufaddc(&vb,0);
+  
+  if (!replace)
+    parsedb(vb.buf, pdb_recordavailable|pdb_rejectstatus, 0,0,0);
+
+  count= parsedb(sourcefile, pdb_recordavailable|pdb_rejectstatus, 0,0,0);
+
+  if (!f_noact) {
+    writedb(vb.buf,1,0);
+    unlockdatabase(admindir);
+  }
+  
+  printf("Information about %d package(s) was updated.\n",count);
+}
diff --git a/md5sum/Makefile.in b/md5sum/Makefile.in
new file mode 100644 (file)
index 0000000..0cd7f85
--- /dev/null
@@ -0,0 +1,44 @@
+# (-*- Fundamental -*-)
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+mandir = $(prefix)/man/man1
+
+SRC = md5.c md5sum.c
+OBJ = md5.o md5sum.o
+HDR = md5.h
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib $(XLIBS)
+ALL_CFLAGS = -I../lib -I.. @DEFS@ $(CFLAGS)
+
+.SUFFIXES:     .c .o
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+all:           md5sum
+
+md5sum:                md5.o md5sum.o
+               $(CC) $(LDFLAGS) -o md5sum md5.o md5sum.o
+
+clean:
+               rm -f *.o core md5sum
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
+               $(INSTALL_PROGRAM) -s md5sum $(bindir)/md5sum
+               $(INSTALL_DATA) md5sum.1 $(mandir)/md5sum.1
diff --git a/md5sum/md5.c b/md5sum/md5.c
new file mode 100644 (file)
index 0000000..0ac9d19
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#include <string.h>            /* for memcpy() */
+#include <sys/types.h>         /* for stupid systems */
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "config.h"
+#include "md5.h"
+
+#ifdef WORDS_BIGENDIAN
+void
+byteSwap(UWORD32 *buf, unsigned words)
+{
+       md5byte *p = (md5byte *)buf;
+
+       do {
+               *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
+                       ((unsigned)p[1] << 8 | p[0]);
+               p += 4;
+       } while (--words);
+}
+#else
+#define byteSwap(buf,words)
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bytes[0] = 0;
+       ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
+{
+       UWORD32 t;
+
+       /* Update byte count */
+
+       t = ctx->bytes[0];
+       if ((ctx->bytes[0] = t + len) < t)
+               ctx->bytes[1]++;        /* Carry from low to high */
+
+       t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
+       if (t > len) {
+               memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+               return;
+       }
+       /* First chunk is an odd size */
+       memcpy((md5byte *)ctx->in + 64 - t, buf, t);
+       byteSwap(ctx->in, 16);
+       MD5Transform(ctx->buf, ctx->in);
+       buf += t;
+       len -= t;
+
+       /* Process data in 64-byte chunks */
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               byteSwap(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(md5byte digest[16], struct MD5Context *ctx)
+{
+       int count = ctx->bytes[0] & 0x3f;       /* Number of bytes in ctx->in */
+       md5byte *p = (md5byte *)ctx->in + count;
+
+       /* Set the first char of padding to 0x80.  There is always room. */
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 56 bytes (-8..55) */
+       count = 56 - 1 - count;
+
+       if (count < 0) {        /* Padding forces an extra block */
+               memset(p, 0, count + 8);
+               byteSwap(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               p = (md5byte *)ctx->in;
+               count = 56;
+       }
+       memset(p, 0, count);
+       byteSwap(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ctx->in[14] = ctx->bytes[0] << 3;
+       ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+       MD5Transform(ctx->buf, ctx->in);
+
+       byteSwap(ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+        (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
+{
+       register UWORD32 a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+#endif
diff --git a/md5sum/md5.h b/md5sum/md5.h
new file mode 100644 (file)
index 0000000..021766c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define md5byte unsigned char
+
+struct MD5Context {
+       UWORD32 buf[4];
+       UWORD32 bytes[2];
+       UWORD32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
+
+#endif /* !MD5_H */
diff --git a/md5sum/md5sum.1 b/md5sum/md5sum.1
new file mode 100644 (file)
index 0000000..c5d5943
--- /dev/null
@@ -0,0 +1,70 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH MD5SUM 1 "29th November 1995" "Lankester et al" "Debian GNU/Linux"
+.SH NAME
+md5sum \- generates or checks MD5 message digests
+
+.SH SYNOPSIS
+.B md5sum
+[-bv] [-c [file]] | [file...]
+
+.SH DESCRIPTION
+.B md5sum
+generates or checks MD5 checksums. The algorithm to generate the
+checksum is reasonably fast and strong enough for most cases. Exact
+specification of the algorithm is in
+.I RFC 1321.
+
+Normally
+.B md5sum
+generates checksums of all files given to it as a parameter and prints
+the checksums followed by the filenames. If, however,
+.B -c
+is specified, only one filename parameter is allowed. This file should
+contain checksums and filenames to which these checksums refer to, and
+the files listed in that file are checked against the checksums listed
+there. See option
+.B -c
+for more information.
+
+.SS OPTIONS
+.TP
+.B -b
+Use binary mode. In unix environment, only difference between this and
+the normal mode is an asterix preceding the filename in the output.
+.TP
+.B -c
+Check md5sum of all files listed in
+.I file
+against the checksum listed in the same file. The actual format of that
+file is the same as output of
+.B md5sum.
+That is, each line in the file describes a file. A line looks like:
+
+.B <MD5 checksum>  <filename>
+
+So, for example, a file containing checksum for this manpage would look
+like(don't worry, if the checkusum doesn't match, there is a minor
+problem in keeping it up to date):
+
+.B c6514f34ffe6e1ce146e1f17db2c0f90  md5sum.1
+.TP
+.B -v
+Be more verbose. Print filenames when checking (with -c).
+
+.SH BUGS
+The related MD4 message digest algorithm was broken in October 1995.
+MD5 isn't looking as secure as it used to.
+
+This manpage is not quite accurate and has formatting inconsistent
+with other manpages.
+
+.B md5sum
+does not accept standard options like
+.BR -\-\help .
+
+.SH AUTHOR
+
+.B md5sum
+was originally written by Branko Lankester, and modified afterwards by
+Colin Plumb and Ian Jackson (ijackson@gnu.ai.mit.edu). Manual page was
+added by Juho Vuori (javuori@cc.helsinki.fi)
diff --git a/md5sum/md5sum.c b/md5sum/md5sum.c
new file mode 100644 (file)
index 0000000..cec2be7
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * md5sum.c    - Generate/check MD5 Message Digests
+ *
+ * Compile and link with md5.c.  If you don't have getopt() in your library
+ * also include getopt.c.  For MSDOS you can also link with the wildcard
+ * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC)
+ * so that you can use wildcards on the commandline.
+ *
+ * Written March 1993 by Branko Lankester
+ * Modified June 1993 by Colin Plumb for altered md5.c.
+ * Modified Feburary 1995 by Ian Jackson for use with Colin Plumb's md5.c.
+ * This file is in the public domain.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "md5.h"
+
+#ifdef UNIX
+#define        FOPRTXT "r"
+#define        FOPRBIN "r"
+#else
+#ifdef VMS
+#define        FOPRTXT "r","ctx=stm"
+#define        FOPRBIN "rb","ctx=stm"
+#else
+#define        FOPRTXT "r"
+#define        FOPRBIN "rb"
+#endif
+#endif
+
+extern char *optarg;
+extern int optind;
+
+void usage();
+void print_digest();
+int mdfile(FILE *fp, unsigned char *digest);
+int do_check(FILE *chkf);
+
+char *progname;
+int verbose = 0;
+int bin_mode = 0;
+
+void
+main(int argc, char **argv)
+{
+       int opt, rc = 0;
+       int check = 0;
+       FILE *fp;
+       unsigned char digest[16];
+
+       progname = *argv;
+       while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
+               switch (opt) {
+                       case 'c': check = 1; break;
+                       case 'v': verbose = 1; break;
+                       case 'b': bin_mode = 1; break;
+                       default: usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if (check) {
+               switch (argc) {
+                       case 0: fp = stdin; break;
+                       case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
+                                       perror(*argv);
+                                       exit(2);
+                               }
+                               break;
+                       default: usage();
+               }
+               exit(do_check(fp));
+       }
+       if (argc == 0) {
+               if (mdfile(stdin, digest)) {
+                       fprintf(stderr, "%s: read error on stdin\n", progname);
+                       exit(2);
+               }
+               print_digest(digest);
+               printf("\n");
+               exit(0);
+       }
+       for ( ; argc > 0; --argc, ++argv) {
+               if (bin_mode)
+                       fp = fopen(*argv, FOPRBIN);
+               else
+                       fp = fopen(*argv, FOPRTXT);
+               if (fp == NULL) {
+                       perror(*argv);
+                       rc = 2;
+                       continue;
+               }
+               if (mdfile(fp, digest)) {
+                       fprintf(stderr, "%s: error reading %s\n", progname, *argv);
+                       rc = 2;
+               } else {
+                       print_digest(digest);
+                       printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
+               }
+               fclose(fp);
+       }
+       exit(rc);
+}
+
+void
+usage()
+{
+       fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n");
+       fprintf(stderr, "Generates or checks MD5 Message Digests\n");
+       fprintf(stderr, "    -c  check message digests (default is generate)\n");
+       fprintf(stderr, "    -v  verbose, print file names when checking\n");
+       fprintf(stderr, "    -b  read files in binary mode\n");
+       fprintf(stderr, "The input for -c should be the list of message digests and file names\n");
+       fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n");
+       exit(2);
+}
+
+int
+mdfile(FILE *fp, unsigned char *digest)
+{
+       unsigned char buf[1024];
+       struct MD5Context ctx;
+       int n;
+
+       MD5Init(&ctx);
+       while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
+               MD5Update(&ctx, buf, n);
+       MD5Final(digest, &ctx);
+       if (ferror(fp))
+               return -1;
+       return 0;
+}
+
+void
+print_digest(unsigned char *p)
+{
+       int i;
+
+       for (i = 0; i < 16; ++i)
+               printf("%02x", *p++);
+}
+
+int
+hex_digit(int c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'a' && c <= 'f')
+               return c - 'a' + 10;
+       return -1;
+}
+
+int
+get_md5_line(FILE *fp, unsigned char *digest, char *file)
+{
+       char buf[1024];
+       int i, d1, d2, rc;
+       char *p = buf;
+
+       if (fgets(buf, sizeof(buf), fp) == NULL)
+               return -1;
+
+       for (i = 0; i < 16; ++i) {
+               if ((d1 = hex_digit(*p++)) == -1)
+                       return 0;
+               if ((d2 = hex_digit(*p++)) == -1)
+                       return 0;
+               *digest++ = d1*16 + d2;
+       }
+       if (*p++ != ' ')
+               return 0;
+       /*
+        * next char is an attribute char, space means text file
+        * if it's a '*' the file should be checked in binary mode.
+        */
+       if (*p == ' ')
+               rc = 1;
+       else if (*p == '*')
+               rc = 2;
+       else {
+               fprintf(stderr, "%s: unrecognized line: %s", progname, buf);
+               return 0;
+       }
+       ++p;
+       i = strlen(p);
+       if (i < 2 || i > 255)
+               return 0;
+       p[i-1] = '\0';
+       strcpy(file, p);
+       return rc;
+}
+
+int
+do_check(FILE *chkf)
+{
+       int rc, ex = 0, failed = 0, checked = 0;
+       unsigned char chk_digest[16], file_digest[16];
+       char filename[256];
+       FILE *fp;
+       int flen = 14;
+
+       while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
+               if (rc == 0)    /* not an md5 line */
+                       continue;
+               if (verbose) {
+                       if (strlen(filename) > flen)
+                               flen = strlen(filename);
+                       fprintf(stderr, "%-*s ", flen, filename);
+               }
+               if (bin_mode || rc == 2)
+                       fp = fopen(filename, FOPRBIN);
+               else
+                       fp = fopen(filename, FOPRTXT);
+               if (fp == NULL) {
+                       fprintf(stderr, "%s: can't open %s\n", progname, filename);
+                       ex = 2;
+                       continue;
+               }
+               if (mdfile(fp, file_digest)) {
+                       fprintf(stderr, "%s: error reading %s\n", progname, filename);
+                       ex = 2;
+                       fclose(fp);
+                       continue;
+               }
+               fclose(fp);
+               if (memcmp(chk_digest, file_digest, 16) != 0) {
+                       if (verbose)
+                               fprintf(stderr, "FAILED\n");
+                       else
+                               fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename);
+                       ++failed;
+               } else if (verbose)
+                       fprintf(stderr, "OK\n");
+               ++checked;
+       }
+       if (verbose && failed)
+               fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked);
+       if (!checked) {
+               fprintf(stderr, "%s: no files checked\n", progname);
+               return 3;
+       }
+       if (!ex && failed)
+               ex = 1;
+       return ex;
+}
diff --git a/methods/Makefile.in b/methods/Makefile.in
new file mode 100644 (file)
index 0000000..47b5d83
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+libdir = $(prefix)/lib
+dpkglibdir = $(libdir)/dpkg
+methodsdir = $(dpkglibdir)/methods
+datadir = /var/lib/dpkg
+methodsdatadir = $(datadir)/methods
+methodsmnt = $(datadir)/methods/mnt
+
+SCRIPTS = setup update install
+METHODS = disk floppy
+DESCS =        disk.desc.harddisk disk.desc.mounted disk.desc.cdrom \
+       disk.desc.nfs floppy.desc.floppy
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+all:
+
+install:
+               set -e; for m in $(METHODS) ; do \
+                       d=$(methodsdir)/$$m ; \
+                       test -d $$d || mkdir $$d ; \
+                       e=$(methodsdatadir)/$$m ; \
+                       test -d $$e || mkdir $$e ; \
+                       $(INSTALL_DATA) $$m.names $$d/names ; \
+                       for s in $(SCRIPTS) ; do \
+                               $(INSTALL_PROGRAM) $$m.$$s $$d/$$s ; \
+                       done ; \
+               done
+               set -e; for x in $(DESCS) ; do \
+                       d=`echo $$x | sed -e 's:\.:/:'` ; \
+                       $(INSTALL_DATA) $$x $(methodsdir)/$$d ; \
+               done
+
+clean:
+               rm -f core
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
diff --git a/methods/disk.desc.cdrom b/methods/disk.desc.cdrom
new file mode 100644 (file)
index 0000000..b400abb
--- /dev/null
@@ -0,0 +1,3 @@
+Installation from a CD-ROM containing a Debian distribution.  The
+CD-ROM may be or not be mounted already; it should contain a standard
+ISO9660 CD-ROM filesystem.
diff --git a/methods/disk.desc.harddisk b/methods/disk.desc.harddisk
new file mode 100644 (file)
index 0000000..ba45750
--- /dev/null
@@ -0,0 +1,9 @@
+Installation from filesystem on a hard disk partition that's not
+currently mounted.
+
+The partition should contain the Packages.gz file from each
+distribution area being installed (usually stable, contrib and
+non-free) as well as the corresponding binary/*/*.deb files.
+
+The easiest way to get this is to make a (partial) copy of the
+distribution site's directory hierarchy, if possible.
diff --git a/methods/disk.desc.mounted b/methods/disk.desc.mounted
new file mode 100644 (file)
index 0000000..b980d70
--- /dev/null
@@ -0,0 +1,12 @@
+Installation from a directory on a filesystem that has already been
+mounted.  If the options available for mounting things automatically
+are inadequate for your needs you'll need to get a shell command
+prompt (for example by switching VT using Alt-F<n> or quitting
+dselect) and use it to mount the filesystem before continuing.
+
+The area you're installing from should contain the Packages.gz file
+from each distribution area being installed (usually stable, contrib
+and non-free) as well as the corresponding binary/*/*.deb files.
+
+The easiest way to do get this is to make a (partial) copy of the
+distribution site's directory hierarchy, if possible.
diff --git a/methods/disk.desc.nfs b/methods/disk.desc.nfs
new file mode 100644 (file)
index 0000000..77bb640
--- /dev/null
@@ -0,0 +1,9 @@
+Installation across the network, from an NFS server which not
+currently mounted.
+
+The server should have contain the Packages.gz file from each
+distribution area being installed (usually stable, contrib and
+non-free) as well as the corresponding binary/*/*.deb files.
+
+The easiest way for them to get this is to make a (partial) copy of
+the distribution site's directory hierarchy, if possible.
diff --git a/methods/disk.install b/methods/disk.install
new file mode 100644 (file)
index 0000000..a14cc39
--- /dev/null
@@ -0,0 +1,127 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/disk"
+
+. ./shvar.$option
+
+xit=1
+trap '
+       if [ -n "$umount" ]
+       then
+               umount "$umount" >/dev/null 2>&1
+       fi
+       exit $xit
+' 0
+
+if [ -n "$p_blockdev" ]
+then
+       umount="$p_mountpoint"
+       mount -rt "$p_fstype" -o nosuid,nodev "$p_blockdev" "$p_mountpoint"
+fi
+
+if [ -n "$p_nfs" ]
+then
+       umount="$p_mountpoint"
+       mount -rt nfs "$p_nfs" -o nosuid,nodev "$p_mountpoint"
+fi
+
+case "$p_mountpoint" in
+*/ )   binaryprefix="$p_mountpoint" ;;
+'' )   binaryprefix="" ;;
+* )    binaryprefix="$p_mountpoint/" ;;
+esac
+
+predep="$vardir/predep-package"
+while true
+do
+       set +e
+       dpkg --predep-package >"$predep"
+       rc=$?
+       set -e
+       if test $rc = 1; then break; fi
+       test $rc = 0
+
+       perl -e '
+               ($binaryprefix,$predep) = @ARGV;
+               $binaryprefix =~ s,/*$,/, if length($binaryprefix);
+               open(P,"< $predep") || die "cannot open $predep: $!\n";
+               while (<P>) {
+                       s/\s*\n$//;
+                       $package= $_ if s/^Package: //i;
+                       @filename= split(/ /,$_) if s/^Filename: //i;
+                       @msdosfilename= split(/ /,$_) if s/^MSDOS-Filename: //i;
+               }
+               length($package) || die "internal error - no package";
+               @filename || die "internal error - no filename";
+               @filename==@msdosfilename || !@filename || !@msdosfilename ||
+                       die "internal error - mismatch >@filename< >@msdosfilename<";
+               @invoke=(); $|=1;
+               for ($i=0; $i<=$#filename; $i++) {
+                       $ppart= $i+1;
+                       print "Looking for part $ppart of $package ... ";
+                       if (-f "$binaryprefix$filename[$i]") {
+                               $print= $filename[$i];
+                               $invoke= "$binaryprefix$filename[$i]";
+                       } elsif (-f "$binaryprefix$msdosfilename[$i]") {
+                               $print= $msdosfilename[$i];
+                               $invoke= "$binaryprefix$msdosfilename[$i]";
+                       } else {
+                               $base= $filename[$i]; $base =~ s,.*/,,;
+                               $msdosbase= $msdosfilename[$i]; $msdosbase =~ s,.*/,,;
+                               defined($c= open(X,"-|")) ||
+                                       die "failed to fork for find: $!\n";
+                               if (!$c) {
+                                       exec("find", length($binaryprefix)
+                                            ? $binaryprefix : ".","-follow",
+                                            "-name",$base,"-o","-name",$msdosbase);
+                                       die "failed to exec find: $!\n";
+                               }
+                               while (chop($invoke= <X>)) { last if -f $invoke; }
+                               $print= $invoke;
+                               if (substr($print,0,length($binaryprefix)+1) eq
+                                   "$binaryprefix/") {
+                                       $print= substr($print,length($binaryprefix));
+                               }
+                       }
+                       if (!length($invoke)) {
+                               print STDERR "
+
+Oh dear, I need to install or upgrade $package, but I don'\''t see
+the appropriate file(s) anywhere.  I'\''m expecting version $version or
+later, as that is listed in the Packages file.
+
+Perhaps you downloaded it with an unexpected name, or something.
+In any case, you must find the file(s) and then either place it with
+the correct filename(s) (as listed in the Packages file or in
+/var/lib/dpkg/available) and rerun the installation, or upgrade the
+package by using `dpkg --install --auto-deconfigure'\'' by hand.
+
+";
+                               exit(1);
+                       }
+                       print "$print\n";
+                       push(@invoke,$invoke);
+               }
+               print "Running dpkg -iB for $package ...\n";
+               exec("dpkg","-iB","--",@invoke);
+               die "failed to exec dpkg: $!\n";
+       ' -- "$binaryprefix$p_main_binary" "$predep"
+done
+
+for f in main ctb nf lcl
+do
+       eval 'this_binary=$p_'$f'_binary'
+       if [ -z "$this_binary" ]; then continue; fi
+       echo Running dpkg -iGROEB "$binaryprefix$this_binary"
+       dpkg -iGROEB "$binaryprefix$this_binary"
+done
+
+echo -n 'Installation OK.  Hit RETURN.  '
+read response
+
+xit=0
diff --git a/methods/disk.names b/methods/disk.names
new file mode 100644 (file)
index 0000000..1f55b78
--- /dev/null
@@ -0,0 +1,4 @@
+30 cdrom Install from a CD-ROM.
+35 nfs Install from an NFS server (not yet mounted).
+40 harddisk Install from a hard disk partition (not yet mounted).
+42 mounted Install from a filesystem which is already mounted.
diff --git a/methods/disk.setup b/methods/disk.setup
new file mode 100644 (file)
index 0000000..5a69200
--- /dev/null
@@ -0,0 +1,562 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/disk"
+tp=/tmp/ddm$$
+
+xit=1
+trap '
+       rm -f $tp.?
+       if [ -n "$umount" ]
+       then
+               umount "$umount" >/dev/null 2>&1
+       fi
+       exit $xit
+' 0
+
+if ls -d "$tp.?" >/dev/null 2>&1
+then
+       rm $tp.?
+fi
+
+yesno () {
+       while true
+       do
+               echo -n "$2 [$1]  "
+               read response
+               if [ -z "$response" ]
+               then
+                       response="$1"
+               fi
+               case "$response" in
+               [Nn]*)  yesno=no ; return ;;
+               [Yy]*)  yesno=yes ; return ;;
+               esac
+       done
+}
+
+getblockdev () {
+       mountpoint="$vardir/methods/mnt"
+       if [ -z "$defaultdevice" ]
+       then
+               defaultdevice="$newdefaultdevice"
+       elif [ "$defaultdevice" != "$newdefaultdevice" ]
+       then
+               echo \
+       "Last time you specified installation from $defaultdevice."
+       fi
+       promptstring="$1"
+       while [ -z "$blockdevice" ]
+       do
+               echo -n "$promptstring [$defaultdevice]:  "
+               read response
+               if [ -z "$response" ]
+               then
+                       response="$defaultdevice"
+               fi
+               if ! [ -b "$response" ]
+               then
+                       echo "$response is not a block device."; continue
+               fi
+               tryblockdevice="$response"
+               if [ $option = cdrom ]
+               then
+                       fstype=iso9660
+               elif [ $option = harddisk ]
+               then
+                       blockbase="`echo \"$tryblockdevice\" | sed -e 's/[0-9]\{1,\}$//'`"
+                       set +e
+                       echo -e "p\nq\n" | fdisk "$blockbase" 2>/dev/null >$tp.f
+                       set -e
+                       proposeddevice="$tryblockdevice" perl -ne '
+next unless /^ *Device +Boot +Begin +Start +End +Blocks +Id +System *$/i .. !/\S/;
+next unless s:^/\S+:: && $& eq $ENV{"proposeddevice"};
+next unless s/^ +(\* +)?\d+ +\d+ +\d+ +\d+\+? +//;
+next unless m/^([0-9a-f]{1,2}) /i;
+%types= ( "1","msdos", "4","msdos", "6","msdos", "7","hpfs", "80","minix",
+          "81","minix", "83","ext2" );
+print $types{$1}; exit(0);     ' <$tp.f >$tp.m
+                       defaultfstype="`cat $tp.m`"
+                       if [ -n "$defaultfstype" ]
+                       then
+                               cat <<END
+The partition table for $blockbase claims that $tryblockdevice
+contains filesystem type $defaultfstype.
+END
+                               if ! grep "     $defaultfstype$" /proc/filesystems >/dev/null
+                               then
+                                       echo \
+       "Your kernel does not appear to support that filesystem type."
+                                       defaultfstype=""
+                               fi
+                       fi
+                       echo -n "Supported filesystems: "
+                       sed -e 's/^.*   / /' /proc/filesystems | tr '\n' ' '
+                       echo -n "
+Enter filesystem type (for $tryblockdevice) [$defaultfstype]:  "
+                       read fstype
+                       if [ -z "$fstype" ]
+                       then
+                               fstype="$defaultfstype"
+                       fi
+               fi
+               umount="$mountpoint"
+               if mount -rt "$fstype" -o nosuid,nodev "$tryblockdevice" "$mountpoint"
+               then
+                       echo
+                       blockdevice="$tryblockdevice"
+               else
+                       umount=""
+                       echo \
+       "Unable to mount $tryblockdevice on $mountpoint, type $fstype."
+               fi
+       done
+}
+
+outputparam () {
+       echo "$2" | sed -e "s/'/'\\\\''/; s/^/$1='/; s/$/'/" >&3
+}
+
+intrkey="`stty -a | sed -n 's/.*intr = \([^;]*\);.*/\1/p'`"
+echo "
+If you make a mistake, use the interrupt key ($intrkey) to abort.
+"
+
+# State variables, `best first'
+#  {main,ctb,nf,lcl}_{packages,binary}
+#   Empty before we've found them or if they're not available,
+#   set to the relevant bit under mountpoint otherwise.
+#  hierbase
+#   A directory containing a Debian FTP site mirror tree.
+#  mountpoint
+#   The mountpoint for the filesystem containing the stuff
+#   empty or unset if we don't know yet, or if we haven't mounted anything;
+#   may also be empty if `directory' was set.
+#  blockdevice
+#   The actual block device to mount.
+#  fstype
+#   The filesystem type to use.
+#  defaultdevice
+#   The default block device to mount.
+
+p_usedevel=no
+if [ -f shvar.$option ]
+then
+       . ./shvar.$option
+       defaultdevice="$p_blockdev"
+       defaultnfsserver="$p_nfsserver"
+       defaultnfsrempath="$p_nfsrempath"
+       usedevel="$p_usedevel"
+fi
+
+if [ $option = cdrom ]
+then
+       mount >$tp.m
+       sed -n 's/ ([^)]*)$//; s/^[^ ]* on //; s/ type iso9660$//p' <$tp.m >$tp.l
+       ncdroms=`wc -l <$tp.l`
+       if [ $ncdroms -gt 1 ]
+       then
+               response=""
+               while [ -z "$response" ]
+               do
+                       echo \
+       'Several CD-ROMs (or other ISO9660 filesystems) are mounted:'
+                       egrep 'type iso9660 \([^)]*\)$' <$tp.m | nl
+                       echo -n \
+       'Is it any of these ?  Type a number, or `n'\'' for none.  '
+                       read response
+                       response="`echo \"$response\" | sed -e 's/[     ]*$//'`"
+                       if expr "$response" : '[0-9][0-9]*$' >/dev/null && \
+                          [ $response -ge 1 -a $response -le $ncdroms ]
+                       then
+                               mountpoint="`sed -n $response'p' <$tp.l`"
+                               echo
+                       elif expr "$response" : '[Nn]' >/dev/null
+                       then
+                               mountpoint=""
+                       else
+                               response=""
+                       fi
+               done
+       elif [ $ncdroms = 1 ]
+       then
+               mountpoint="`cat $tp.l`"
+               perl -ne 'print if s/ type iso9660 \([^)]*\)$// && s/ on .*$//;' \
+                       <$tp.m >$tp.d
+               blockdevice="`cat $tp.d`"
+               yesno yes \
+       "I see a CD-ROM: $blockdevice, mounted on $mountpoint.  Is it the right one ?"
+               if [ $yesno = no ]
+               then
+                       echo 'Unmounting it ...'
+                       umount="$mountpoint"
+                       while true
+                       do
+                               echo -n \
+       'Please insert the right disc, and hit return:  '
+                               read response
+                               if mount -rt iso9660 -o nosuid,nodev \
+                                       "$blockdevice" "$mountpoint"
+                               then
+                                       echo
+                                       break
+                               fi
+                       done
+               fi
+       fi
+       if [ -z "$mountpoint" ]
+       then
+               if [ -b /dev/cdrom ]
+               then
+                       echo \
+       'I see that /dev/cdrom exists and is a block device.'
+                       newdefaultdevice=/dev/cdrom
+               fi
+               getblockdev 'Insert the CD-ROM and enter the block device name'
+       fi
+fi
+
+if [ $option = nfs ]
+then
+       mountpoint="$vardir/methods/mnt"
+       while [ -z "$nfsserver" ]
+       do
+               echo -n \
+"What is the name of the NFS server ? [$defaultnfsserver]  "
+               read response
+               if [ -z "$response" -a -n "$defaultnfsserver" ]
+               then
+                       response="$defaultnfsserver"
+               fi
+               if [ -z "$response" ]; then continue; fi
+               if [ -x /usr/bin/rpcinfo ]
+               then
+                       if rpcinfo -u "$response" mountd >/dev/null
+                       then
+                               nfsserver="$response"
+                       else
+                               echo "$response appears not to be an NFS server."
+                       fi
+               elif [ -x /bin/ping ]
+               then
+                       if ping -q -c 1 "$response" | grep -q ', 1 packets received'
+                       then
+                               nfsserver="$response"
+                       else
+                               echo "$response appears to be down or nonexistent."
+                       fi
+               else
+                       echo \
+"(I can't check that now because there is no /usr/bin/rpcinfo or /bin/ping.)"
+                       nfsserver="$response"
+               fi
+       done
+       while [ -z "$nfsrempath" ]
+       do
+               echo -n "
+What is the pathname on the NFS server of the filesystem with
+the Debian files ? [$defaultnfsrempath]  "
+               read response
+               if [ -z "$response" -a -n "$defaultnfsrempath" ]
+               then
+                       response="$defaultnfsrempath"
+               else
+                       response="`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`"
+               fi
+               umount="$mountpoint"
+               if mount -rt nfs -o nosuid,nodev "$nfsserver:$response" "$mountpoint"
+               then
+                       echo
+                       nfsrempath="$response"
+               else
+                       umount=""
+                       echo \
+"Unable to mount NFS filesystem $nfsserver:$response."
+               fi
+       done
+       nfs="$nfsserver:$nfsrempath"
+fi
+
+if [ $option = harddisk ]
+then
+       set +e
+       echo -e 'p\nq\n' | fdisk /dev/hda 2>/dev/null >$tp.f
+       if [ $? != 0 ]
+       then
+               echo -e 'p\nq\n' | fdisk /dev/sda 2>/dev/null >$tp.f
+       fi
+       set -e
+       perl -ne '
+next unless /^ *Device +Boot +Begin +Start +End +Blocks +Id +System *$/i .. !/\S/;
+next unless / [146] +DOS \d+-bit \S+$/;
+next unless m:^/\S+:;
+print $&;              ' <$tp.f >$tp.d
+       newdefaultdevice="`cat $tp.d`"
+       echo "
+I need to know which disk partition contains the distribution files;
+disk partitions are specified by the block device name in Linux."
+       if [ -n "$newdefaultdevice" ]
+       then
+               echo \
+"By the way, $newdefaultdevice looks like a DOS partition."
+       fi
+       getblockdev "Enter the partition's block device name"
+fi
+
+if [ -n "$mountpoint" ]
+then
+       # We must have $mountpoint
+       if [ $option = cdrom ]
+       then
+               echo \
+'All directory names should be entered relative to the root of the CD-ROM.
+'
+       elif [ $option = nfs ]
+       then
+               echo \
+"All directory names should be entered relative to the root of the NFS
+filesystem, ie relative to $nfsrempath on the server.
+"
+       else
+               echo \
+"All directory names should be entered relative to the root of the
+$fstype filesystem on $blockdevice.
+"
+       fi
+fi
+
+while true
+do
+       if [ $option = cdrom ]
+       then
+               echo \
+"I would like to know where on the CD-ROM the top level of the Debian
+distribution is - this will usually contain the Packages-Master file.
+
+If the CD-ROM is badly organised and doesn't have a straightforward copy of
+the distribution you may answer \`none' and we'll go through the parts
+I need individually."
+       else
+               echo \
+"In order to make it easy for me to find the relevant files I'd ideally
+like to install from a straightforward copy of the Debian distribution.
+To use this I'll need to know where the top level of that copy of the
+distribution is - this directory usually contains the Packages-Master file.
+
+If you do not have a straightforward copy of the distribution available
+just answer \`none' and we'll go through the parts I need individually."
+       fi
+       defhierbase=none
+       if [ -n "$p_hierbase" ]
+       then
+               if [ -d "$mountpoint/$p_hierbase/stable/binary" ]
+               then
+                       echo "
+Last time you said \`$p_hierbase', and that looks plausible."
+                       defhierbase="$p_hierbase"
+               else
+                       echo "
+Last time you said \`$p_hierbase', but that doesn't look plausible,
+since \`$p_hierbase/stable/binary' doesn't seem to exist."
+               fi
+       fi
+       if [ none = "$defhierbase" -a -d "$mountpoint/debian/stable/binary" ]
+       then
+               echo "
+\`/debian' exists and looks plausible, so that's the default."
+               defhierbase=/debian
+       fi
+       echo -n \
+"Distribution top level ? [$defhierbase]  "
+       read response
+       if [ -z "$response" ]
+       then
+               response="$defhierbase"
+       fi
+       if [ none = "$response" ]
+       then
+               hierbase=""
+               break
+       elif [ -d "$mountpoint/$response/stable/binary" ]
+       then
+               hierbase="`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`"
+               break
+       fi
+       echo \
+"$response/stable/binary does not exist.
+"
+done
+
+whichmain=stable
+if [ -n "$hierbase" ]
+then
+       if [ -d "$mountpoint/$hierbase/development/binary" ]
+       then
+               echo \
+'
+Both a stable released distribution and a work-in-progress
+development tree are available for installation.  Would you like to
+use the unreleased development tree (this is only recommended for
+experts who like to live dangerously and want to help with testing) ?'
+               yesno "$p_usedevel" 'Use unreleased development distribution ?'
+               usedevel="$response"
+               if [ "$usedevel" = yes ]
+               then
+                       whichmain=development
+               fi
+       else
+               usedevel=no
+       fi
+       echo
+fi
+
+check_binary () {
+       # args: area-in-messages directory
+       if ! [ -d "$mountpoint/$2" ]
+       then
+               echo "\`$2' does not exist."
+               return
+       fi
+       if ! find "$mountpoint/$2" -follow -name '*.deb' -print \
+               2>/dev/null | head -1 | grep . >/dev/null
+       then
+               echo "\`$2' does not contain any *.deb packages.  Hmmpf."
+               return
+       fi
+       echo "Using \`$2' as $1 binary dir."
+       this_binary="$2"
+}
+
+find_area () {
+       # args: area-in-messages area-in-vars subdirectory-in-hier
+       #       last-time-binary last-time-packages
+       this_binary=''
+       this_packages=''
+       if [ -n "$hierbase" ]
+       then
+               check_binary $1 "$hierbase/$3/binary"
+       fi
+       if [ $option = cdrom -a $2 = nf -a -z "$this_binary" ]
+       then
+               echo '
+Note: most CD-ROM distributions of Debian do not include programs
+available in the `non-free'\'' directory of the distribution site.
+This is because these programs have copyrights that prevent
+distribution for profit on a CD-ROM - ie they are not free software.
+If you wish to install these programs you'\''ll have to get them from an
+alternative source.'
+       fi
+       while [ -z "$this_binary" ]
+       do
+               defaultbinary="$4"
+               echo "
+Which directory contains the *.deb packages from the $1 distribution
+area (this directory is named \`$3/binary' on the distribution site) ?"
+               if [ $2 != main ]
+               then
+                       if [ -z "$defaultbinary" ]
+                       then
+                               defaultbinary=none
+                       fi
+                       echo \
+"Say \`none' if this area is not available."
+               fi
+               echo -n \
+"Enter _$1_ binary dir. [$4]
+ ?  "
+               read response
+               if [ -z "$response" -a -n "$defaultbinary" ]
+               then
+                       response="$defaultbinary"
+               fi
+               if [ none = "$response" -a $2 != main ]
+               then
+                       break
+               fi
+               case "$response" in
+               '' | none)      continue                ;;
+               esac
+               check_binary $1 "`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`"
+       done
+       if [ -n "$this_binary" ]
+       then
+               for f in Packages.gz packages.gz Packages packages
+               do
+                       if [ -f "$mountpoint/$this_binary/$f" ]
+                       then
+                               echo "Using \`$this_binary/$f' for $1."
+                               this_packages="$this_binary/$f"
+                               break
+                       fi
+               done
+               while [ -z "$this_packages" ]
+               do
+                       echo -n "
+I can't find the $1 \`Packages' file.  The information in the
+\`Packages' file is important for package selection during new
+installations, and is very useful for upgrades.
+
+If you overlooked it when downloading you should do get it now and
+return to this installation procedure when you have done so: you will
+find one Packages file and one Packages.gz file -- either will do --
+in the \`binary' subdirectory of each area on the FTP sites and
+CD-ROMs.
+
+You need a separate Packages file from each of the distribution areas
+you wish to install.
+
+Where is the _$1_ \`Packages' file (if none is available, say\`none')
+[$5]
+ ?  "
+                       read response
+                       if [ -z "$response" -a -n "$5" ]
+                       then
+                               response="$5"
+                       fi
+                       case "$response" in
+                       '')             continue                        ;;
+                       none)           break                           ;;
+                       /*)             this_packages="$response"       ;;
+                       *)              this_packages="/$response"      ;;
+                       esac
+               done
+       fi
+       eval $2'_binary="$this_binary"'
+       eval $2'_packages="$this_packages"'
+}
+
+find_area main main "$whichmain" "$p_main_binary" "$p_main_packages"
+find_area contrib ctb contrib "$p_ctb_binary" "$p_ctb_packages"
+find_area non-free nf non-free "$p_nf_binary" "$p_nf_packages"
+find_area local lcl local "$p_lcl_binary" "$p_lcl_packages"
+
+echo -n '
+Hit RETURN to continue.  '
+read response
+
+exec 3>shvar.$option.new
+
+outputparam p_blockdev "$blockdevice"
+outputparam p_fstype "$fstype"
+outputparam p_mountpoint "$mountpoint"
+outputparam p_nfsserver "$nfsserver"
+outputparam p_nfsrempath "$nfsrempath"
+outputparam p_nfs "$nfs"
+outputparam p_hierbase "$hierbase"
+outputparam p_usedevel "$usedevel"
+outputparam p_main_packages "$main_packages"
+outputparam p_main_binary "$main_binary"
+outputparam p_ctb_packages "$ctb_packages"
+outputparam p_ctb_binary "$ctb_binary"
+outputparam p_nf_packages "$nf_packages"
+outputparam p_nf_binary "$nf_binary"
+outputparam p_lcl_packages "$lcl_packages"
+outputparam p_lcl_binary "$lcl_binary"
+
+mv shvar.$option.new shvar.$option
+
+xit=0
diff --git a/methods/disk.update b/methods/disk.update
new file mode 100644 (file)
index 0000000..68a5259
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/disk"
+
+. ./shvar.$option
+
+if [ -z "$p_main_packages" -a -z "$p_ctb_packages" -a \
+     -z "$p_nf_packages" -a -z "$p_lcl_packages " ]
+then
+       echo '
+No Packages files available, cannot update available packages list.
+Hit RETURN to continue.  '
+       read response
+       exit 0
+fi
+
+xit=1
+trap '
+       rm -f packages-{main,ctb,nf,lcl}
+       if [ -n "$umount" ]
+       then
+               umount "$umount" >/dev/null 2>&1
+       fi
+       exit $xit
+' 0
+
+if [ -n "$p_blockdev" ]
+then
+       umount="$p_mountpoint"
+       mount -rt "$p_fstype" -o nosuid,nodev "$p_blockdev" "$p_mountpoint"
+fi
+
+if [ -n "$p_nfs" ]
+then
+       umount="$p_mountpoint"
+       mount -rt nfs "$p_nfs" -o nosuid,nodev "$p_mountpoint"
+fi
+
+for f in main ctb nf lcl
+do
+       eval 'this_packages=$p_'$f'_packages'
+       if [ -z "$this_packages" ]; then continue; fi
+       case "$p_mountpoint" in
+       */ )    packagesfile="$p_mountpoint$this_packages" ;;
+       '' )    packagesfile="$this_packages" ;;
+       * )     packagesfile="$p_mountpoint/$this_packages" ;;
+       esac
+       case "$packagesfile" in
+       *.gz | *.Z | *.GZ | *.z)
+               echo -n "Uncompressing $packagesfile ... "
+               zcat <"$packagesfile" >packages-$f
+               echo done.
+               dpkg --merge-avail packages-$f
+               ;;
+       '')
+               ;;
+       *)
+               dpkg --merge-avail "$packagesfile"
+               ;;
+       esac
+done
+
+echo -n 'Update OK.  Hit RETURN.  '
+read response
+
+xit=0
diff --git a/methods/floppy.desc.floppy b/methods/floppy.desc.floppy
new file mode 100644 (file)
index 0000000..0bd6329
--- /dev/null
@@ -0,0 +1,9 @@
+Installation using a pile of floppies, at least one of which (usually
+the first) contains the Packages file, and the rest of which contain
+the binary *.deb files.
+
+If you are installing software from the `non-free' or `contrib'
+directories as well as the main Debian distribution you must have the
+Packages files for those areas on separate floppies.  The usual way to
+do this is to put each Packages file on the first floppy which contains
+packages from the relevant area.
diff --git a/methods/floppy.install b/methods/floppy.install
new file mode 100644 (file)
index 0000000..a9823a4
--- /dev/null
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/floppy"
+
+mountpoint="$vardir/methods/mnt"
+
+. ./shvar.$option
+
+help () {
+       echo '
+Now I need the disks containing the packages to be installed.
+I shall keep telling you what is left to be done, in case that
+is helpful deciding which floppy to use.'
+}
+
+help
+
+xit=1
+trap '
+       if [ -n "$umount" ]
+       then
+               umount "$umount"
+       fi
+       exit $xit
+' 0
+
+while [ -z "$goconfigure" ]
+do
+       yet="`dpkg --yet-to-unpack`"
+       if [ -z "$yet" ]
+       then
+               echo '
+All packages unpacked, going on to configure them.
+'
+               goconfigure=1
+               continue
+       fi
+       echo '
+Packages yet to be unpacked:'
+       echo "$yet"
+       dpkg-split -l
+               
+       echo -n '
+Insert a disk containing *.deb files, or type q to quit.  '
+       read response
+       case "$response" in
+       [Qq] | [Qq][Uu][Ii][Tt] )
+               goconfigure=1
+               ;;
+       * )
+               umount="$defaultfloppy"
+               if mount -rt "$defaultfstype" "$defaultfloppy" "$mountpoint"
+               then
+                       echo
+                       dpkg --unpack -GROEB "$mountpoint" || true
+                       umount "$defaultfloppy"
+               fi
+               umount=""
+               ;;
+       esac
+done
+
+if ! [ -z "$yet" ]
+then
+       response=""
+       while [ -z "$response" ]
+       do
+               echo -n '
+Not all the packages have yet been unpacked.  Shall I try to
+proceed with configuration anyay ?  If any of the packages which
+have been unpacked so far depend on any that haven'\''t then you'\''ll
+see error messages; on the other hand if you say no those packages that
+could have been configured will not be.   (y/n)  '
+               read response
+               case "$response" in
+               [Nn]* )
+                       echo '
+OK.  Be sure to come back to this, because unpacked-but-not-configured
+packages are not in general useable.  Alternatively, use the Configure
+option on the dselect menu.
+'
+                       exit 1
+                       ;;
+               [Yy]* )
+                       ;;
+               * )
+                       response=""
+                       ;;
+               esac
+       done
+fi
+
+dpkg --configure --pending
+
+xit=0
diff --git a/methods/floppy.names b/methods/floppy.names
new file mode 100644 (file)
index 0000000..72b189a
--- /dev/null
@@ -0,0 +1 @@
+50 floppy Install from a pile of floppy disks.
diff --git a/methods/floppy.setup b/methods/floppy.setup
new file mode 100644 (file)
index 0000000..8c16cd2
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/floppy"
+
+defaultfloppy=fd0
+defaultfstype=msdos
+if [ -f shvar.$option ]
+then
+       . ./shvar.$option
+       defaultfloppy="`echo \"$defaultfloppy\" | sed -e 's,^/dev/,,'`"
+fi
+
+while [ -z "$floppy" ]
+do
+       echo -n '
+Which floppy disk drive do you wish to use ?  Give the name in
+/dev (eg fd0) or the MSDOS drive letter (eg A).  ['$defaultfloppy']  '
+       read floppy
+       if [ -z "$floppy" ]
+       then
+               floppy="$defaultfloppy"
+       fi
+       case "$floppy" in
+       [ABab] | [ABab]: )
+               floppy="`echo $floppy | \
+                       sed -e 's/:$//; s,^[Aa],/dev/fd0,; s,^[Bb],/dev/fd1,'`"
+               ;;
+       /* )
+               ;;
+       * )
+               floppy="/dev/$floppy"
+               ;;
+       esac
+       if ! [ -b "$floppy" ]
+       then
+               echo "$floppy is not a block device."
+               floppy=""
+       fi
+done
+
+while [ -z "$fstype" ]
+do
+       echo -n '
+What kind of filesystem is on the floppies ?  ['$defaultfstype']  '
+       read fstype
+       if [ -z "$fstype" ]
+       then
+               fstype="$defaultfstype"
+       fi
+       if ! grep "     $fstype$" /proc/filesystems >/dev/null
+       then
+               echo \
+       "Your kernel does not appear to support that filesystem type."
+               fstype=""
+       fi
+done
+
+echo
+
+outputparam () {
+       echo "$2" | sed -e "s/'/'\\\\''/; s/^/$1='/; s/$/'/" >&3
+}
+
+exec 3>shvar.$option.new
+
+outputparam defaultfloppy "$floppy"
+outputparam defaultfstype "$fstype"
+
+mv shvar.$option.new shvar.$option
+
+exit 0
diff --git a/methods/floppy.update b/methods/floppy.update
new file mode 100644 (file)
index 0000000..1903089
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+set -e
+vardir="$1"
+method=$2
+option=$3
+
+cd "$vardir/methods/floppy"
+
+mountpoint="$vardir/methods/mnt"
+
+. ./shvar.$option
+
+help () {
+       echo '
+First I need the disk(s) which contain the Packages file(s) for
+the parts of the archive you wish to be able to install.  If you
+want to install packages from the non-free and contrib areas of
+the FTP site you need a floppy with a Packages file for each of
+those, in addition to the main Packages file for the main Debian
+distribution.  If you don'\''t then you just need one Packages file.'
+}
+
+help
+
+xit=1
+trap '
+       if [ -n "$umount" ]
+       then
+               umount "$umount"
+       fi
+       exit $xit
+' 0
+
+tryupdate () {
+       if [ $success = 1 ]; then return; fi
+       if [ ! -f "$mountpoint/Packages" ]; then
+               echo "$mountpoint/Packages does not exist.";
+               return
+       fi
+       if dpkg --merge-avail "$mountpoint/Packages"
+       then
+               success=1
+               echo '
+You may incorporate another Packages file from another floppy if you wish.'
+       fi
+}
+
+while [ $xit = 1 ]
+do
+       echo -n '
+Insert a disk containing a Packages file, or type q to quit.  '
+       read response
+       case "$response" in
+       [Qq] | [Qq][Uu][Ii][Tt] )
+               xit=0
+               ;;
+       * )
+               umount="$defaultfloppy"
+               if mount -rt "$defaultfstype" "$defaultfloppy" "$mountpoint"
+               then
+                       success=0
+                       tryupdate Packages
+                       tryupdate packages
+                       tryupdate PACKAGES
+                       umount "$defaultfloppy"
+               fi
+               umount=""
+               ;;
+       esac
+done
+
+echo '
+OK, continuting with installation.'
+
+xit=0
diff --git a/methods/hd.setup b/methods/hd.setup
new file mode 100755 (executable)
index 0000000..a238c52
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/perl
+#
+#      Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
+#
+#   this script 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 script 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 script; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+print "Is the partition to install from mounted? [Y] ";
+$ans = <STDIN>;
+if ($ans =~ /^[Nn]/) {
+       do {
+               do {
+                       print "Which device should I mount?  /dev/";
+                       $drive = <STDIN>;
+                       chop $drive;
+                       $drive =~ tr/[A-Z]/[a-z]/;
+               } while (! -b "/dev/$drive");
+       
+               $mpoint = "/mnt";
+               do {
+                       print "Where should I mount it? (Please use full path) [$mpoint] ";
+                       $newmp = <STDIN>;
+                       chop $newmp;
+                       $mpoint = $newmp if ($newmp !~ /^$/);
+               } while (($mpoint !~ ?^/?) || (! -d $mpoint)); 
+       
+               print "These filesystems are available:";
+               open(FILESYS, "</proc/filesystems");
+               $systems = " ";
+               while (<FILESYS>) {
+                       next if /^nodev/;
+                       chop;
+                       /(\w+)/;
+                       $systems .= "$1 ";
+               }
+               print "$systems\n";
+               do {
+                       print "What filesystem is the partition to mount? [ext2] ";
+                       $filesys = <STDIN>;
+                       chop $filesys;
+                       $filesys = "ext2" if ($filesys =~ /^$/);
+                       $filesys =~ tr/[A-Z]/[a-z]/;
+               } while ($systems !~ /\s$filesys\s/);
+
+               do {
+                       print "Any other options for mount? ";
+                       print "(eg. '-o ro' for cdrom, must start with '-') [] ";
+                       $opts = <STDIN>;
+                       chop $opts;
+               } while ($opts !~ /^$/ && $opts !~ /^\-/);
+       
+               $command = "/bin/mount -t $filesys $opts /dev/$drive $mpoint";
+               print "I will now run \"$command\"\n";
+       #       system("$command");
+       } while ($?);
+}                              # I never knew how hard I could make it to mount a drive. 
+
+# Assumedly, the drive is now mounted
+
+open (STATUS, ">/var/lib/dpkg/methods/hd/hd.status") || die "Can't open hd.status";
+do {
+       print "What is the full path to the 'available' file?\n";
+       print "This file is found as Packages on the ftp site and CDROM";
+       print "Use 'none' if you don't have one.";
+       $avail = <STDIN>;
+       chop $avail;
+} while (! -f $avail || $avail !~ ?^/? || $avail !~ /none/);
+
+do{
+       print "What is the full path to the base directory ";
+       print "containing the .deb packages?\n";
+       $debpath = <STDIN>;
+       chop $debpath;
+} while(! -d $debpath || $debpath !~ ?^/?);
+
+print STATUS "AVAIL:   $avail\n";
+print STATUS "DEBDIR:  $debpath\n";
+close (STATUS);
+exit (0);
diff --git a/methods/hd.unpack b/methods/hd.unpack
new file mode 100755 (executable)
index 0000000..ad22c6b
--- /dev/null
@@ -0,0 +1,36 @@
+# Return associative array of fields from control file $file.
+sub slurp
+{
+  local ($file) = @_;
+  local (%controlinfo);
+  local (%ci);
+
+  open (CONTROL, $file) || return 1;
+
+  # Get entire text of control file.
+  undef $/; $* = 1; $_ = <CONTROL>;
+
+  # Join lines.
+  s/\n[ \t]+/ /g;
+
+  # Split on fields.
+  %controlinfo = ('PRESTUFF', split (/^(\S+):\s*/));
+
+  $/ = "\n"; $* = 0;
+  foreach $key (keys %controlinfo)
+    {
+      $key2 = $key; $key2 =~ y/A-Z/a-z/;
+      chop ($controlinfo{$key}) if (/\n/);
+      $ci{$key2} = $controlinfo{$key};
+    }
+
+  return %ci;
+}
+
+$file = "/var/lib/dpkg/methods/hd/hd.status";
+%info = slurp($file);
+$dpkg = "dpkg --auto --unpack --no-auto-select ";
+$dpkg .= "--refuse downgrade --skip-same-version";
+
+system("$dpkg $info{'debdir'}");
+
diff --git a/methods/hd.update b/methods/hd.update
new file mode 100755 (executable)
index 0000000..98bf56b
--- /dev/null
@@ -0,0 +1,37 @@
+# Return associative array of fields from control file $file.
+sub slurp
+{
+  local ($file) = @_;
+  local (%controlinfo);
+  local (%ci);
+
+  open (CONTROL, $file) || return 1;
+
+  # Get entire text of control file.
+  undef $/; $* = 1; $_ = <CONTROL>;
+
+  # Join lines.
+  s/\n[ \t]+/ /g;
+
+  # Split on fields.
+  %controlinfo = ('PRESTUFF', split (/^(\S+):\s*/));
+
+  $/ = "\n"; $* = 0;
+  foreach $key (keys %controlinfo)
+    {
+      $key2 = $key; $key2 =~ y/A-Z/a-z/;
+      chop ($controlinfo{$key}) if (/\n/);
+      $ci{$key2} = $controlinfo{$key};
+    }
+
+  return %ci;
+}
+
+$file = "/var/lib/dpkg/methods/hd/hd.status";
+%info = slurp($file);
+open (IN, "<$info{'avail'}") || die "can't open $info{'avail'}";
+open (OUT, ">/var/lib/dpkg/available") || die "can't open /var/lib/dpkg/available";
+print OUT while (<IN>);
+close IN;
+close OUT;
+
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..0e29377
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make directory hierarchy. 
+# Written by Noah Friedman <friedman@prep.ai.mit.edu>
+# Public domain.
+
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   oIFS="${IFS}"
+   # Some sh's can't handle IFS=/ for some reason.
+   IFS='%'
+   set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
+   IFS="${oIFS}"
+
+   pathcomp=''
+
+   for d in ${1+"$@"} ; do
+     pathcomp="${pathcomp}${d}"
+
+     if test ! -d "${pathcomp}"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "${pathcomp}" || errstatus=$?
+     fi
+
+     pathcomp="${pathcomp}/"
+   done
+done
+
+exit $errstatus
+
+# eof
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
new file mode 100644 (file)
index 0000000..e3fe56d
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+bindir = $(prefix)/bin
+sbindir = $(prefix)/sbin
+datadir = /var/lib/dpkg
+altsdatadir = $(datadir)/alternatives
+mandir = $(prefix)/man
+man1dir = $(mandir)/man1
+man8dir = $(mandir)/man8
+man1 = 1
+man8 = 8
+libdir = $(prefix)/lib
+dpkglibdir = $(libdir)/dpkg
+etcdir= /etc
+altsetcdir = $(etcdir)/alternatives
+perlpath = @perlpath@
+
+MAN1 =  dpkg-name
+EXC =   dpkg-name
+MAN8 = update-rc.d start-stop-daemon update-alternatives install-info
+SBIN = update-rc.d start-stop-daemon update-alternatives install-info \
+       dpkg-scanpackages dpkg-divert
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+.SUFFIXES:     .pl .sh .gzuue
+
+.pl:
+               sed <$@.pl 's:^#!/usr/bin/perl:#!$(perlpath):' \
+                 | ../insert-version.pl >$@.new
+               chmod +x $@.new
+               mv $@.new $@
+
+.sh:
+               sed <$@.sh 's:^dpkglibdir=/usr/lib/dpkg$$:dpkglibdir=$(dpkglibdir):' \
+                 | ../insert-version.pl >$@.new
+               mv $@.new $@
+
+.gzuue:
+               uudecode <$@.gzuue
+               gunzip <$@.gz >$@.new
+               test ! -x $@.gz || chmod +x $@.new
+               rm $@.gz
+               mv $@.new $@
+
+all:           $(EXC) $(SBIN)
+
+clean:
+               rm -f $(EXC) $(SBIN) core *.new
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*# i386elf-hello-world.gz
+
+install:       all
+               for f in $(EXC) ; do $(INSTALL_PROGRAM) $$f $(bindir)/$$f ; done
+               for f in $(MAN1) ; do $(INSTALL_DATA) $$f.1 $(man1dir)/$$f.$(man1) ; done
+               for f in $(SBIN) ; do $(INSTALL_PROGRAM) $$f $(sbindir)/$$f ; done
+               for f in $(MAN8) ; do $(INSTALL_DATA) $$f.8 $(man8dir)/$$f.$(man8) ; done
diff --git a/scripts/dpkg-divert.pl b/scripts/dpkg-divert.pl
new file mode 100644 (file)
index 0000000..dff1854
--- /dev/null
@@ -0,0 +1,220 @@
+#!/usr/bin/perl --
+
+#use POSIX; &ENOENT;
+sub ENOENT { 2; }
+# Sorry about this, but POSIX.pm isn't necessarily available
+
+$version= '1.0.11'; # This line modified by Makefile
+sub usageversion {
+    print(STDERR <<END)
+Debian GNU/Linux dpkg-divert $version.  Copyright (C) 1995
+Ian Jackson.  This is free software; see the GNU General Public Licence
+version 2 or later for copying conditions.  There is NO warranty.
+
+Usage:
+ dpkg-divert [options] [--add] <file>
+ dpkg-divert [options] --remove <file>
+ dpkg-divert [options] --list [<glob-pattern>]
+
+Options:  --package <package> | --local  --divert <divert-to>  --rename
+          --quiet  --test  --help|--version  --admindir <directory>
+
+<package> is the name of a package whose copy of <file> will not be diverted.
+<divert-to> is the name used by other packages' versions.
+--local specifies that all packages' versions are diverted.
+--rename causes dpkg-divert to actually move the file aside (or back).
+
+When adding, default is --local and --divert <original>.distrib.
+When removing, --package or --local and --divert must match if specified.
+Package preinst/postrm scripts should always specify --package and --divert.
+END
+        || &quit("failed to write usage: $!");
+}
+
+$admindir= '/var/lib/dpkg';
+$testmode= 0;
+$dorename= 0;
+$verbose= 1;
+$mode='';
+$|=1;
+
+sub checkmanymodes {
+    return unless $mode;
+    &badusage("two modes specified: $_ and --$mode");
+}
+
+while (@ARGV) {
+    $_= shift(@ARGV);
+    last if m/^--$/;
+    if (!m/^-/) {
+        unshift(@ARGV,$_); last;
+    } elsif (m/^--(help|version)$/) {
+        &usageversion; exit(0);
+    } elsif (m/^--test$/) {
+        $testmode= 1;
+    } elsif (m/^--rename$/) {
+        $dorename= 1;
+    } elsif (m/^--quiet$/) {
+        $verbose= 0;
+    } elsif (m/^--local$/) {
+        $package= ':';
+    } elsif (m/^--add$/) {
+        &checkmanymodes;
+        $mode= 'add';
+    } elsif (m/^--remove$/) {
+        &checkmanymodes;
+        $mode= 'remove';
+    } elsif (m/^--list$/) {
+        &checkmanymodes;
+        $mode= 'list';
+    } elsif (m/^--divert$/) {
+        @ARGV || &badusage("--divert needs a divert-to argument");
+        $divertto= shift(@ARGV);
+        $divertto =~ m/\n/ && &badusage("divert-to may not contain newlines");
+    } elsif (m/^--package$/) {
+        @ARGV || &badusage("--package needs a package argument");
+        $package= shift(@ARGV);
+        $divertto =~ m/\n/ && &badusage("package may not contain newlines");
+    } elsif (m/^--admindir$/) {
+        @ARGV || &badusage("--admindir needs a directory argument");
+        $admindir= shift(@ARGV);
+    } else {
+        &badusage("unknown option \`$_'");
+    }
+}
+
+$mode='add' unless $mode;
+
+open(O,"$admindir/diversions") || &quit("cannot open diversions: $!");
+while(<O>) {
+    s/\n$//; push(@contest,$_);
+    $_=<O>; s/\n$// || &badfmt("missing altname");
+    push(@altname,$_);
+    $_=<O>; s/\n$// || &badfmt("missing package");
+    push(@package,$_);
+}
+close(O);
+
+if ($mode eq 'add') {
+    @ARGV == 1 || &badusage("--add needs a single argument");
+    $file= $ARGV[0];
+    $file =~ m/\n/ && &badusage("file may not contain newlines");
+    $divertto= "$file.distrib" unless defined($divertto);
+    $package= ':' unless defined($package);
+    for ($i=0; $i<=$#contest; $i++) {
+        if ($contest[$i] eq $file || $altname[$i] eq $file ||
+            $contest[$i] eq $divertto || $altname[$i] eq $divertto) {
+            if ($contest[$i] eq $file && $altname[$i] eq $divertto &&
+                $package[$i] eq $package) {
+                print "Leaving \`",&infon($i),"'\n" if $verbose > 0;
+                exit(0);
+            }
+            &quit("\`".&infoa."' clashes with \`".&infon($i)."'");
+        }
+    }
+    push(@contest,$file);
+    push(@altname,$divertto);
+    push(@package,$package);
+    print "Adding \`",&infon($#contest),"'\n" if $verbose > 0;
+    &checkrename($file,$divertto);
+    &save;
+    &dorename($file,$divertto);
+    exit(0);
+} elsif ($mode eq 'remove') {
+    @ARGV == 1 || &badusage("--remove needs a single argument");
+    $file= $ARGV[0];
+    for ($i=0; $i<=$#contest; $i++) {
+        next unless $file eq $contest[$i];
+        &quit("mismatch on divert-to\n  when removing \`".&infoa."'\n  found \`".
+              &infon($i)."'") if defined($divertto) && $altname[$i] ne $divertto;
+        &quit("mismatch on package\n  when removing \`".&infoa."'\n  found \`".
+              &infon($i)."'") if defined($package) && $package[$i] ne $package;
+        print "Removing \`",&infon($i),"'\n" if $verbose > 0;
+        $orgfile= $contest[$i];
+        $orgdivertto= $altname[$i];
+        @contest= (($i > 0 ? @contest[0..$i-1] : ()),
+                   ($i < $#contest ? @contest[$i+1,$#contest] : ()));
+        @altname= (($i > 0 ? @altname[0..$i-1] : ()),
+                   ($i < $#altname ? @altname[$i+1,$#altname] : ()));
+        @package= (($i > 0 ? @package[0..$i-1] : ()),
+                   ($i < $#package ? @package[$i+1,$#package] : ()));
+        &checkrename($orgdivertto,$orgfile);
+        &dorename($orgdivertto,$orgfile);
+        &save;
+        exit(0);
+    }
+    print "No diversion \`",&infoa,"', none removed\n" if $verbose > 0;
+    exit(0);
+} elsif ($mode eq 'list') {
+    @ilist= @ARGV ? @ARGV : ('*');
+    while (defined($_=shift(@ilist))) {
+        s/\W/\\$&/g;
+        s/\\\?/./g;
+        s/\\\*/.*/g;
+        push(@list,"^$_\$");
+    }
+    $pat= join('$|^',@list);
+    for ($i=0; $i<=$#contest; $i++) {
+        next unless ($contest[$i] =~ m/$pat/o ||
+                     $altname[$i] =~ m/$pat/o ||
+                     $package[$i] =~ m/$pat/o);
+        print &infon($i),"\n";
+    }
+    exit(0);
+} else {
+    &quit("internal error - bad mode \`$mode'");
+}
+
+sub infol {
+    return (($_[2] eq ':' ? "<local>" : length($_[2]) ? "$_[2]" : "<any>").
+            ": $_[0]".
+            (length($_[1]) ? " -> $_[1]" : ""));
+}
+
+sub checkrename {
+    return unless $dorename;
+    ($rsrc,$rdest) = @_;
+    (@ssrc= lstat($rsrc)) || $! == &ENOENT ||
+        &quit("cannot stat old name \`$rsrc': $!");
+    (@sdest= lstat($rdest)) || $! == &ENOENT ||
+        &quit("cannot stat new name \`$rdest': $!");
+    if (@ssrc && @sdest &&
+        !($ssrc[0] == $sdest[0] && $ssrc[1] == $sdest[1])) {
+        &quit("rename involves overwriting \`$rdest' with\n".
+              "  different file \`$rsrc', not allowed");
+    }
+}
+
+sub dorename {
+    return unless $dorename;
+    if (@ssrc) {
+        if (@sdest) {
+            unlink($rsrc) || &quit("rename: remove duplicate old link \`$rsrc': $!");
+        } else {
+            rename($rsrc,$rdest) || &quit("rename: rename \`$rsrc' to \`$rdest': $!");
+        }
+    }
+}            
+    
+sub save {
+    return if $testmode;
+    open(N,"> $admindir/diversions-new") || &quit("create diversions-new: $!");
+    for ($i=0; $i<=$#contest; $i++) {
+        print(N "$contest[$i]\n$altname[$i]\n$package[$i]\n")
+            || &quit("write diversions-new: $!");
+    }
+    close(N) || &quit("close diversions-new: $!");
+    unlink("$admindir/diversions-old") ||
+        $! == &ENOENT || &quit("remove old diversions-old: $!");
+    link("$admindir/diversions","$admindir/diversions-old") ||
+        $! == &ENOENT || &quit("create new diversions-old: $!");
+    rename("$admindir/diversions-new","$admindir/diversions")
+        || &quit("install new diversions: $!");
+}
+
+sub infoa { &infol($file,$divertto,$package); }
+sub infon { &infol($contest[$i],$altname[$i],$package[$i]); }
+
+sub quit { print STDERR "dpkg-divert: @_\n"; exit(2); }
+sub badusage { print STDERR "dpkg-divert: @_\n\n"; &usageversion; exit(2); }
+sub badfmt { &quit("internal error: $admindir/diversions corrupt: $_[0]"); }
diff --git a/scripts/dpkg-name.1 b/scripts/dpkg-name.1
new file mode 100644 (file)
index 0000000..b474feb
--- /dev/null
@@ -0,0 +1,60 @@
+.\" This is an -*- nroff -*- source file.
+.\" dpkg-name and this manpage are Copyright 1995,1996 by Erick Branderhorst.
+.\"
+.\" This is free software; see the GNU General Public Licence version 2
+.\" or later for copying conditions.  There is NO warranty.
+.TH dpkg-name 1 "January 1996" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+dpkg\-name \- rename Debian packages to full package names
+.SH SYNOPSIS
+.B dpkg\-name [\-h|\-\-help] [\-V|\-\-version] [\-L|\-\-license] [--] [files]
+.SH DESCRIPTION
+.PP
+This manual page documents the
+.B dpkg\-name 
+sh script which provides an easy way to rename
+.B Debian
+packages into their full package names. A full package name consists
+of <package>-<version>[-<revision>].deb as specified in the control
+file of the package.
+.SH EXAMPLES
+.TP
+.B dpkg-name toedeledokie
+The file `toedeledokie' will be renamed to emacs-19.29-4.deb or
+something similar (depending on whatever information is in the control
+part of `toedeledokie').
+.TP
+.B find /root/debian/ \-name '*.deb' | xargs dpkg\-name
+All files with the extension `deb' in the directory /root/debian and
+its subdirectory's will be renamed by dpkg\-name if required.
+.SS OPTIONS
+.TP
+.B "\-h, \-\-help"
+Print a usage message and exit successfully.
+.TP
+.B "\-v, \-\-version"
+Print version information and exit successfully.
+.TP
+.B "\-l, \-\-license"
+Print copyright information and (a reference to GNU) license
+information and exit successfully.
+.SH BUGS?
+Successfully tested on
+.B Debian GNU/Linux 
+systems only. Some packages don't follow the name structure
+<package>-<version>[-<revision>].deb. Packages renamed by dpkg-name
+will follow this structure. Generally this will have no impact on how
+packages are installed by dselect/dpkg.
+.SH SEE ALSO
+.BR deb (5),
+.BR deb-control (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dpkg-deb (8).
+.SH COPYRIGHT
+Copyright 1995,1996 Erick Branderhorst.
+.B dpkg-name
+is free software; see the GNU General Public Licence version 2 or
+later for copying conditions. There is
+.B no
+warranty.
diff --git a/scripts/dpkg-name.sh b/scripts/dpkg-name.sh
new file mode 100755 (executable)
index 0000000..294010a
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/sh
+
+set -e
+
+prog="`basename \"${0}\"`"
+version="0.11"; # This line modified by Makefile
+purpose="rename Debian packages to full package names"
+
+license () {
+echo "# ${prog} ${version} -- ${purpose}
+# Copyright (C) 1995,1996 Erick Branderhorst <branderhorst@heel.fgg.eur.nl>.
+
+# This 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 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 file
+# /usr/doc/copyright/GPL for more details."
+}
+
+stderr () {
+       echo "${prog}: $@" >/dev/stderr;
+}
+
+show_version () {
+       echo "${prog} version ${version} -- ${purpose}";
+}
+
+usage () {
+       echo "Usage: ${prog} file[s]
+  ${purpose}
+  file.deb changes to <package>-<version>[-<revision>].deb
+  -h|--help|-v|--version|-l|--license  Show help/version/license"
+}
+
+rename () {
+       if [ -f "$1" ];
+       then
+               if p=`dpkg-deb -f -- "$1" package`;
+               then
+                       p="$p-"`dpkg-deb -f -- "$1" version`;
+                       r=`dpkg-deb -f -- "$1" revision`;
+                       if [ -z "$r" ];
+                       then
+                               r=`dpkg-deb -f -- "$1" package_revision`;
+                       fi
+                       if [ -n "$r" ];
+                       then
+                               p=$p-$r;
+                       fi
+                       p=`echo $p|sed 's/ //g'`
+                       p=`dirname "$1"`"/"$p.deb       
+                       if [ $p -ef "$1" ];                                                                     # same device and inode numbers
+                       then
+                               stderr "skipping \`"$1"'";
+                       elif [ -f $p ];
+                       then
+                               stderr "can't move \`"$1"' to existing file";
+                       elif `mv -- "$1" $p`;
+                       then
+                               echo "moved \``basename "$1"`' to \`${p}'";
+                       else
+                               stderr "hmm how did this happen?";
+                       fi
+               fi
+       else
+               stderr "can't deal with \`"$1"'";
+  fi
+}
+
+if [ $# = 0 ]; then usage; exit 0; fi  
+for arg
+do
+       case "$arg" in
+               --version|-v) show_version; exit 0;;
+               --help|-[h?]) usage; exit 0;;
+               --licen[cs]e|-l) license; exit 0;;
+               --) shift; 
+                       for arg 
+                       do 
+                               rename "$arg"; 
+                       done; exit 0;;
+               *) rename "$arg";;
+       esac
+done
+exit 0;
+
+# Local variables:
+# tab-width: 2
+# End:
+
diff --git a/scripts/dpkg-scanpackages.pl b/scripts/dpkg-scanpackages.pl
new file mode 100755 (executable)
index 0000000..efb6a6e
--- /dev/null
@@ -0,0 +1,178 @@
+#!/usr/bin/perl --
+# usage:
+#  dpkg-scanpackages .../binary .../noverride pathprefix >.../Packages.new
+#  mv .../Packages.new .../Packages
+#
+# This is the core script that generates Packages files (as found
+# on the Debian FTP site and CD-ROMs).
+#
+# The first argument should preferably be a relative filename, so that
+# the Filename field has good information.
+#
+# Any desired string can be prepended to each Filename value by
+# passing it as the third argument.
+#
+# The noverride file is a series of lines of the form
+# <package> <priority> <section> <maintainer>
+# where the <maintainer> field is optional.  Fields are separated by
+# whitespace.
+
+$version= '1.0.10'; # This line modified by Makefile
+
+%kmap= ('optional','suggests',
+        'recommended','recommends',
+        'class','priority',
+        'package_revision','revision');
+
+%pri= ('priority',300,
+       'section',290,
+       'maintainer',280,
+       'version',270,
+       'depends',250,
+       'recommends',240,
+       'suggests',230,
+       'conflicts',220,
+       'provides',210,
+       'filename',200,
+       'size',180,
+       'md5sum',170,
+       'description',160);
+
+@ARGV==3 || die;
+
+$binarydir= shift(@ARGV);
+-d $binarydir || die $!;
+
+$override= shift(@ARGV);
+-e $override || die $!;
+
+$pathprefix= shift(@ARGV);
+
+open(F,"find $binarydir -name '*.deb' -print |") || die $!;
+while (<F>) {
+    chop($fn=$_);
+    substr($fn,0,length($binarydir)) eq $binarydir || die $fn;
+    open(C,"dpkg-deb -I $fn control |") || die "$fn $!";
+    $t=''; while (<C>) { $t.=$_; }
+    $!=0; close(C); $? && die "$fn $? $!";
+    undef %tv;
+    $o= $t;
+    while ($t =~ s/^\n*(\S+):[ \t]*(.*(\n[ \t].*)*)\n//) {
+        $k= $1; $v= $2;
+        $k =~ y/A-Z/a-z/;
+        if (defined($kmap{$k})) { $k= $kmap{$k}; }
+        $v =~ s/\s+$//;
+        $tv{$k}= $v;
+#print STDERR "K>$k V>$v<\n";
+    }
+    $t =~ m/^\n*$/ || die "$fn $o / $t ?";
+    defined($tv{'package'}) || die "$fn $o ?";
+    $p= $tv{'package'}; delete $tv{'package'};
+    defined($p1{$p}) && die "$fn $p repeat";
+    if (defined($tv{'filename'})) {
+        print(STDERR " ! Package $p (filename $fn) has Filename field !\n") || die $!;
+    }
+    $tv{'filename'}= "$pathprefix$fn";
+    open(C,"md5sum <$fn |") || die "$fn $!";
+    chop($_=<C>); m/^[0-9a-f]{32}$/ || die "$fn \`$_' $!";
+    $!=0; close(C); $? && die "$fn $? $!";
+    $tv{'md5sum'}= $_;
+    defined(@stat= stat($fn)) || die "$fn $!";
+    $stat[7] || die "$fn $stat[7]";
+    $tv{'size'}= $stat[7];
+    if (length($tv{'revision'})) {
+        $tv{'version'}.= '-'.$tv{'revision'};
+        delete $tv{'revision'};
+    }
+    for $k (keys %tv) {
+        $pv{$p,$k}= $tv{$k};
+        $k1{$k}= 1;
+        $p1{$p}= 1;
+    }
+    $_= substr($fn,length($binarydir));
+    s#/[^/]+$##; s#^/*##;
+    $psubdir{$p}= $_;
+    $pfilename{$p}= $fn;
+}
+$!=0; close(F); $? && die "$? $!";
+
+select(STDERR); $= = 1000; select(STDOUT);
+
+format STDERR =
+  ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$packages
+.
+
+sub writelist {
+    $title= shift(@_);
+    return unless @_;
+    print(STDERR " $title\n") || die $!;
+    $packages= join(' ',sort @_);
+    while (length($packages)) { write(STDERR) || die $!; }
+    print(STDERR "\n") || die $!;
+}
+
+@inover=();
+@samemaint=();
+
+open(O,"<$override") || die $!;
+while(<O>) {
+    s/\s+$//;
+    ($p,$priority,$section,$maintainer)= split(/\s+/,$_,4);
+    if (!defined($p1{$p})) {
+        push(@inover,$p);
+        next;
+    }
+    if (length($maintainer)) {
+        if ($pv{$p,'maintainer'} eq $maintainer) {
+            push(@samemaint,"  $p ($maintainer)\n");
+        } else {
+            $pv{$p,'maintainer'}= $maintainer;
+        }
+    }
+    $pv{$p,'priority'}= $priority;
+    $pv{$p,'section'}= $section;
+    if (length($psubdir{$p}) && $section ne $psubdir{$p}) {
+        print(STDERR " !! Package $p has \`Section: $section',".
+                     " but file is in \`$psubdir{$p}' !!\n") || die $!;
+        $ouches++;
+    }
+    $o1{$p}= 1;
+}
+close(O);
+
+if ($ouches) { print(STDERR "\n") || die $!; }
+
+$k1{'maintainer'}= 1;
+$k1{'priority'}= 1;
+$k1{'section'}= 1;
+
+@missingover=();
+
+for $p (sort keys %p1) {
+    if (!defined($o1{$p})) {
+        push(@missingover,$p);
+    }
+    $r= "Package: $p\n";
+    for $k (sort { $pri{$b} <=> $pri{$a} } keys %k1) {
+        next unless length($pv{$p,$k});
+        $r.= "$k: $pv{$p,$k}\n";
+    }
+    $r.= "\n";
+    $written++;
+    print(STDOUT $r) || die $!;
+}
+close(STDOUT) || die $!;
+
+&writelist("** Packages in archive but missing from override file: **",
+           @missingover);
+&writelist("++ Packages appearing in override file but not in archive: ++",
+           @inover);
+if (@samemaint) {
+    print(STDERR
+          " -- Packages specifying same maintainer as override file: --\n",
+          @samemaint,
+          "\n") || die $!;
+}
+
+print(STDERR " Wrote $written entries to output Packages file.\n") || die $!;
diff --git a/scripts/install-info.8 b/scripts/install-info.8
new file mode 100644 (file)
index 0000000..2d88179
--- /dev/null
@@ -0,0 +1,245 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Install-info and this manpage are Copyright 1994 by Ian Jackson.
+.\"
+.\" This is free software; see the GNU General Public Licence version 2
+.\" or later for copying conditions.  There is NO warranty.
+.TH INSTALL-INFO 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+install\-info \- create or update entry in Info directory
+.SH SYNOPSIS
+.B install\-info
+[\-\-version] [\-\-help] [\-\-debug] [\-\-maxwidth=nnn]
+[\-\-section regexp title] [\-\-infodir=xxx] [\-\-align=nnn]
+[\-\-quiet] [\-\-menuentry=xxx] [\-\-description=xxx] [\-\-remove]
+[\-\-] filename
+.SH DESCRIPTION
+.PP
+.B install-info
+makes, updates or removes entries in the Info directory, the
+.B dir
+file.  When updating or creating entries, if no description is
+specified on the command line or in the Info file it attempts to guess
+a description from the contents of the file.
+
+See the description of the
+.B \-\-section
+option for details of where the entry will be placed and a description
+of the expected format of the
+.B dir
+file.
+.SS OPTIONS
+.TP
+.BI "[\-\-] " filename
+Gives the filename of the Info file whose menu entry is to be created,
+updated or removed.  The basename of this filename is used as the
+referent of the menu entry which is created.  This file must therefore
+exist (or be about to be installed, or have previously existed when
+removing an entry) in the same directory as the
+.B dir
+file (see the
+.B \-\-infodir
+option).
+
+If
+.I filename
+ends in
+.B .gz
+it is taken to refer to a file compressed with GNU gzip; if it doesn't
+exist, but a corresponding
+.IB filename .gz
+does, the latter is used instead.
+
+When adding or updating entries the file must exist at the path
+specified (possibly with an additional
+.B .gz
+extension).
+.TP
+.B \-\-remove
+Specifies that the entry for the file
+.I filename
+is to be removed; by default entries are created or updated.
+
+If the removal results in a section becoming empty the section heading
+(and the spare blank line) will be removed as well, unless this is the
+last section in the file or
+.B \-\-keep\-old
+is specified.  See the
+.B \-\-section
+option for details about the expected format of the
+.B dir
+file.
+
+If there are several suitable entries in the
+.B dir
+file only those in the first matching contiguous group will be removed
+and the others silently ignored.
+
+It is not an error for no suitable entry to be found, though
+.B install\-info
+will issue a warning unless the
+.B \-\-quiet
+option was specified.
+
+When
+.B \-\-remove
+is specified the
+.BR \-\-maxwidth ", " \-\-align " and " \-\-calign
+formatting options are silently ignored.
+.TP
+.BI "\-\-section " "regexp title"
+Specifies that, if a new entry is to be made, it should be placed in a
+section of the
+.B dir
+file whose title matches
+.IR regexp .
+If no such section exists one will be created as the second last
+section in the file (see below), with title
+.IR title .
+A section is a part of the
+.B dir
+menu delimited by blank lines; the first line is assumed to be the
+title.
+
+If a new entry is to be created
+.B install-info
+will attempt to insert it within the section according in alphabetic
+order; if the entries in the section aren't already sorted the new
+location within the section will be unpredictable.  The order of
+existing entries will not be changed.
+
+The default is to append new entries to the end of the file.  The last
+section (even if it only consists of the title line) should always
+exist, to ensure that new sections are created in the right place.
+The final section should be titled to reflect the fact that Info files
+with no more well specified location are appended to it.
+
+If there is already an entry for the Info file being installed it is
+replaced in situ with the new entry.
+
+If a section is specified when removing an entry the section is
+ignored and a warning is issued.
+.TP
+.BI \-\-infodir= infodir
+Specifies that the
+.B dir
+file is, and the installed copy of the new Info file was, is or will
+be located in
+.IR infodir .
+The default is
+.BR /usr/info .
+.TP
+.BI \-\-align= nnn
+Specifies that the first line of the description should be indented at
+least
+.I nnn
+characters; extra spaces will be added as required.  If necessary
+because of the length of the
+.B dir
+menu entry details it may be offset more.  The default is 27.
+.TP
+.BI \-\-calign= nnn
+Specifies that the second and subsequent lines of the description
+should be indented at least
+.I nnn
+characters.  The default is 29.
+.TP
+.BI \-\-maxwidth= nnn
+Specifies that the maximum width for the Info file is
+.IR nnn .
+This is used when wordwrapping the descriptive text.
+The default is 79.
+.TP
+.B \-\-quiet
+Prevents the usual display of the new menu entry just before it is
+inserted, and of the messages announcing the replacement and removal
+of existing entries and the creation and deletion of sections.
+.TP
+.B \-\-help
+Causes
+.B install-info
+to display its usage information and exit.
+.TP
+.B \-\-version
+Causes
+.B install-info
+to display its version and copyright information and exit.
+.TP
+.BI \-\-description= xxx
+Specifies that the description to use after the menu entry in new or
+updated entries be
+.IR xxx .
+The default is to use the the value specified in the Info file itself;
+this is found by searching for a section of the form
+.br
+.B START\-INFO\-DIR\-ENTRY
+.br
+.B * Auto-PGP: (auto-pgp).  PGP under GNU Emacs.
+.br
+.B END\-INFO\-DIR\-ENTRY
+
+If the entry found in the Info file itself extends across several
+lines, each giving a menu entry, the text found in the file is used
+verbatim.  In this case the alphabetic ordering scheme is turned off,
+and the entries are inserted at the top of section in question.  In
+this case the
+.BR \-\-menuentry ", " \-\-maxwidth ", " \-\-align ", " \-\-calign
+.RB " and " \-\-menuentry
+options are ignored.
+
+If there is no
+.B dir
+entry in the file the program will try to find a paragraph early in
+the file starting
+.BR "this file documents" .
+It will capitalise the first character of the remainder, and use that.
+
+It is an error for none of these methods to yield a description.
+
+If a description argument is given when
+.B \-\-remove
+is specified it is ignored and a warning is issued.
+.TP
+.BI \-\-menuentry= xxx
+Specifies that the entry in the menu should be
+.IR xxx .
+The default is to use the the value specified in the Info file itself.
+If this is not present the basename of the Info file is used
+.RB "(any " ".info " "is deleted, and the entry is made mixed case)."
+See above for details of the format expected for the menu entry in the
+Info file.
+
+When removing entries the value of the
+.B \-\-menuentry
+option must match the actual menu entry field in the menu item to be
+removed (case not significant).  If
+.B \-\-menuentry
+is omitted no check on the menu entry is done.
+.TP
+.B \-\-keep\-old
+Inhibits the replacement of existing entries and the removal of empty
+sections.
+
+If the file being installed alreay has an entry in the directory the
+old entry will be left alone instead of being replaced; the default is
+to overwrite any old entry found with the newly generated one.
+
+If
+.BR \-\-remove " is specified " \-\-keep\-old
+will prevent the removal of the section heading which would otherwise
+happen if the section is made empty by the removal.
+.TP
+.B \-\-test
+Enables test mode, which inhibits the update of the directory file.
+.TP
+.B \-\-debug
+Enables debugging mode, in which the results of some internal
+processing steps are shown.
+.SH "SEE ALSO"
+emacs(1), info(1), gzip(1)
+.SH COPYRIGHT
+Copyright 1994, Ian Jackson.
+.B install\-info
+is free software; see the GNU General Public Licence version 2 or
+later for copying conditions.  There is
+.I no
+warranty.
diff --git a/scripts/install-info.pl b/scripts/install-info.pl
new file mode 100755 (executable)
index 0000000..0455ab1
--- /dev/null
@@ -0,0 +1,342 @@
+#!/usr/bin/perl --
+
+# fixme: --dirfile option
+# fixme: sort entries
+# fixme: send to FSF ?
+
+$version= '0.93.42.2'; # This line modified by Makefile
+sub version {
+        print STDERR <<END;
+Debian GNU/Linux install-info $version.  Copyright (C) 1994,1995
+Ian Jackson.  This is free software; see the GNU General Public Licence
+version 2 or later for copying conditions.  There is NO warranty.
+END
+}
+
+sub usage {
+    print STDERR <<END;
+usage: install-info [--version] [--help] [--debug] [--maxwidth=nnn]
+             [--section regexp title] [--infodir=xxx] [--align=nnn]
+             [--calign=nnn] [--quiet] [--menuentry=xxx] [--keep-old]
+             [--description=xxx] [--test] [--remove] [--] filename
+END
+}
+
+$infodir='/usr/info';
+$maxwidth=79;
+$align=27;
+$calign=29;
+
+undef $menuentry;
+undef $quiet;
+undef $nowrite;
+undef $keepold;
+undef $description;
+undef $sectionre;
+undef $sectiontitle;
+$0 =~ m|[^/]+$|; $name= $&;
+
+while ($ARGV[0] =~ m/^--/) {
+    $_= shift(@ARGV);
+    last if $eq eq '--';
+    if ($_ eq '--version') {
+        &version; exit 0;
+    } elsif ($_ eq '--quiet') {
+        $quiet=1;
+    } elsif ($_ eq '--test') {
+        $nowrite=1;
+    } elsif ($_ eq '--keep-old') {
+        $keepold=1;
+    } elsif ($_ eq '--remove') {
+        $remove=1;
+    } elsif ($_ eq '--help') {
+        &usage; exit 0;
+    } elsif ($_ eq '--debug') {
+        open(DEBUG,">&STDERR") || exit 1;
+    } elsif ($_ eq '--section') {
+        if (@ARGV < 2) {
+            print STDERR "$name: --section needs two more args\n";
+            &usage; exit 1;
+        }
+        $sectionre= shift(@ARGV);
+        $sectiontitle= shift(@ARGV);
+    } elsif (m/^--maxwidth=([0-9]+)$/) {
+        $maxwidth= $1;
+    } elsif (m/^--align=([0-9]+)$/) {
+        $align= $1;
+    } elsif (m/^--calign=([0-9]+)$/) {
+        $calign= $1;
+    } elsif (m/^--infodir=/) {
+        $infodir=$';
+    } elsif (m/^--menuentry=/) {
+        $menuentry=$';
+    } elsif (m/^--description=/) {
+        $description=$';
+    } else {
+        print STDERR "$name: unknown option \`$_'\n"; &usage; exit 1;
+    }
+}
+
+if (!@ARGV) { &version; print STDERR "\n"; &usage; exit 1; }
+
+$filename= shift(@ARGV);
+if (@ARGV) { print STDERR "$name: too many arguments\n"; &usage; exit 1; }
+
+if ($remove) {
+    print STDERR "$name: --section ignored with --remove\n" if length($sectiontitle);
+    print STDERR "$name: --description ignored with --remove\n" if length($description);
+}
+
+print STDERR "$name: test mode - dir file will not be updated\n"
+    if $nowrite && !$quiet;
+
+umask(umask(0777) & ~0444);
+
+$filename =~ m|[^/]+$|; $basename= $&; $basename =~ s/(\.info)?(\.gz)?$//;
+print DEBUG <<END;
+ infodir=\`$infodir'  filename=\`$filename'  maxwidth=\`$maxwidth'
+ menuentry=\`$menuentry'  basename=\`$basename'
+ description=\`$description' remove=$remove
+END
+
+if (!$remove) {
+
+    if (!-f $filename && -f "$filename.gz" || $filename =~ s/\.gz$//) {
+        $filename= "gzip -d <$filename.gz |";  $pipeit= 1;
+    } else {
+        $filename= "< $filename";
+    }
+
+    if (!length($description)) {
+        
+        open(IF,"$filename") || die "$name: read $filename: $!\n";
+        $asread='';
+        while(<IF>) { last if m/^START-INFO-DIR-ENTRY$/; }
+        while(<IF>) { last if m/^END-INFO-DIR-ENTRY$/; $asread.= $_; }
+        close(IF); &checkpipe;
+        if ($asread =~ m/(\* *[^:]+: *\([^\)]+\).*\. *.*\n){2,}/) {
+            $infoentry= $asread; $multiline= 1;
+            print DEBUG <<END;
+ multiline \`$asread'
+END
+        } elsif ($asread =~ m/^\* *([^:]+):( *\([^\)]+\)\.|:)\s*/) {
+            $menuentry= $1; $description= $';
+            print DEBUG <<END;
+ infile menuentry \`$menuentry' description \`$description'
+END
+        } elsif (length($asread)) {
+            print STDERR <<END;
+$name: warning, ignoring confusing INFO-DIR-ENTRY in file.
+END
+        }
+    }
+
+    if (length($infoentry)) {
+
+        $infoentry =~ m/\n/;
+        print "$`\n" unless $quiet;
+        $infoentry =~ m/^\* *([^:]+): *\(([^\)]+)\)/ || die; # internal error
+        $sortby= $1;  $fileinentry= $2;
+        
+    } else {
+        
+        if (!length($description)) {
+            open(IF,"$filename") || die "$name: read $filename: $!\n";
+            $asread='';
+            while(<IF>) {
+                if (m/^\s*[Tt]his file documents/) {
+                    $asread=$';
+                    last;
+                }
+            }
+            if (length($asread)) {
+                while(<IF>) { last if m/^\s*$/; $asread.= $_; }
+                $description= $asread;
+            }
+            close(IF); &checkpipe;
+        }
+
+        if (!length($description)) {
+            print STDERR <<END;
+No \`START-INFO-DIR-ENTRY' and no \`This file documents'.
+$name: unable to determine description for \`dir' entry - giving up
+END
+            exit 1;
+        }
+
+        $description =~ s/^\s*(.)//;  $_=$1;  y/a-z/A-Z/;
+        $description= $_ . $description;
+
+        if (!length($menuentry)) {
+            $menuentry= $basename;  $menuentry =~ s/\Winfo$//;
+            $menuentry =~ s/^.//;  $_=$&;  y/a-z/A-Z/;
+            $menuentry= $_ . $menuentry;
+        }
+
+        print DEBUG <<END;
+ menuentry=\`$menuentry'  description=\`$description'
+END
+
+        $cprefix= sprintf("* %s: (%s).", $menuentry, $basename);
+        $align--; $calign--;
+        $lprefix= length($cprefix);
+        if ($lprefix < $align) {
+            $cprefix .= ' ' x ($align - $lprefix);
+            $lprefix= $align;
+        }
+        $prefix= "\n". (' 'x $calign);
+        $cwidth= $maxwidth+1;
+
+        for $_ (split(/\s+/,$description)) {
+            $l= length($_);
+            $cwidth++; $cwidth += $l;
+            if ($cwidth > $maxwidth) {
+                $infoentry .= $cprefix;
+                $cwidth= $lprefix+1+$l;
+                $cprefix= $prefix; $lprefix= $calign;
+            }
+            $infoentry.= ' '; $infoentry .= $_;
+        }
+
+        $infoentry.= "\n";
+        print $infoentry unless $quiet;
+        $sortby= $menuentry;  $sortby =~ y/A-Z/a-z/;
+
+    }
+}
+
+if (!link("$infodir/dir","$infodir/dir.lock")) {
+    die "$name: failed to lock dir for editing! $!\n".
+        ($! =~ m/exists/i ? "try deleting $infodir/dir.lock ?\n" : '');
+}
+
+open(OLD,"$infodir/dir") || &ulquit("$name: open $infodir/dir: $!\n");
+@work= <OLD>;
+eof(OLD) || &ulquit("$name: read $infodir/dir: $!\n");
+close(OLD) || &ulquit("$name: close $infodir/dir after read: $!\n");
+while ($work[$#work] !~ m/\S/) { $#work--; }
+
+if (!$remove) {
+
+    for ($i=0; $i<=$#work; $i++) {
+        next unless $work[$i] =~ m/^\* *[^:]+: *\(([^\)]+)\).*\.\s/;
+        last if $1 eq $basename || $1 eq "$basename.info";
+    }
+    for ($j=$i; $j<=$#work+1; $j++) {
+        next if $work[$j] =~ m/^\s+\S/;
+        last unless $work[$j] =~ m/^\* *[^:]+: *\(([^\)]+)\).*\.\s/;
+        last unless $1 eq $basename || $1 eq "$basename.info";
+    }
+
+    if ($i < $j) {
+        if ($keepold) {
+            print "$name: existing entry for \`$basename' not replaced\n" unless $quiet;
+            $nowrite=1;
+        } else {
+            print "$name: replacing existing dir entry for \`$basename'\n" unless $quiet;
+        }
+        $mss= $i;
+        @work= (@work[0..$i-1], @work[$j..$#work]);
+    } elsif (length($sectionre)) {
+        for ($i=0; $i<=$#work && $work[$i] !~ m/^\* *menu/i; $i++) { }
+        $mss= -1;
+        for (; $i<=$#work; $i++) {
+            $_= $work[$i];
+            next if m/^\*/;
+            next unless m/$sectionre/io;
+            $mss= $i+1; last;
+        }
+        if ($mss < 0) {
+            print "$name: creating new section \`$sectiontitle'\n" unless $quiet;
+            for ($i= $#work; $i>=0 && $work[$i] =~ m/\S/; $i--) { }
+            $i >= 0 || &ulquit("$name: nowhere to create new section - giving up\n");
+            @work= (@work[0..$i], "$sectiontitle\n", "\n", @work[$i+1..$#work]);
+            $mss= $i+1;
+        }
+        while ($mss <= $#work) {
+            $work[$mss] =~ m/\S/ || last;
+            $work[$mss] =~ m/^\* *([^:]+):/ || ($mss++, next);
+            last if $multiline;
+            $_=$1;  y/A-Z/a-z/;
+            last if $_ gt $sortby;
+            $mss++;
+        }
+    } else {
+        print "$name: no section specified for new entry, placing at end\n"
+            unless $quiet;
+        $mss= $#work+1;
+    }
+
+    @work= (@work[0..$mss-1], $infoentry, @work[$mss..$#work]);
+    
+} else {
+
+    for ($i=0; $i<=$#work; $i++) {
+        next unless $work[$i] =~ m/^\* *([^:]+): *\((\w[^\)]*)\)/;
+        $tme= $1; $tfile= $2; $match= $&;
+        next unless $tfile eq $basename;
+        last if !length($menuentry);
+        $tme =~ y/A-Z/a-z/;
+        last if $tme eq $menuentry;
+    }
+    for ($j=$i; $j<=$#work+1; $j++) {
+        next if $work[$j] =~ m/^\s+\S/;
+        last unless $work[$j] =~ m/^\* *([^:]+): *\((\w[^\)]*)\)/;
+        $tme= $1; $tfile= $2;
+        last unless $tfile eq $basename;
+        next if !length($menuentry);
+        $tme =~ y/A-Z/a-z/;
+        last unless $tme eq $menuentry;
+    }
+        print DEBUG <<END;
+ i=$i \$work[\$i]=\`$work[$i]' j=$j \$work[\$j]=\`$work[$j]'
+END
+
+    if ($i < $j) {
+        print "$name: deleting entry \`$match ...'\n" unless $quiet;
+        $_= $work[$i-1];
+        unless (m/^\s/ || m/^\*/ || m/^$/ ||
+                $j > $#work || $work[$j] !~ m/^\s*$/) {
+            s/:?\s+$//;
+            if ($keepold) {
+                print "$name: empty section \`$_' not removed\n" unless $quiet;
+            } else {
+                $i--; $j++;
+                print "$name: deleting empty section \`$_'\n" unless $quiet;
+            }
+        }
+        @work= (@work[0..$i-1], @work[$j..$#work]);
+    } else {
+        print "$name: no entry for file \`$basename'".
+              (length($menuentry) ? " and menu entry \`$menuentry'": '').
+              ".\n"
+            unless $quiet;
+    }
+}
+
+if (!$nowrite) {
+    open(NEW,"> $infodir/dir.new") || &ulquit("$name: create $infodir/dir.new: $!\n");
+    print(NEW @work) || &ulquit("$name: write $infodir/dir.new: $!\n");
+    close(NEW) || &ulquit("$name: close $infodir/dir.new: $!\n");
+
+    unlink("$infodir/dir.old");
+    link("$infodir/dir","$infodir/dir.old") ||
+        &ulquit("$name: cannot backup old $infodir/dir, giving up: $!\n");
+    rename("$infodir/dir.new","$infodir/dir") ||
+        &ulquit("$name: install new $infodir/dir: $!\n");
+}
+
+unlink("$infodir/dir.lock") || die "$name: unlock $infodir/dir: $!\n";
+
+sub ulquit {
+    unlink("$infodir/dir.lock") ||
+        warn "$name: warning - unable to unlock $infodir/dir: $!\n";
+    die $_[0];
+}
+
+sub checkpipe {
+    return if !$pipeit || !$? || $?==0x8D00;
+    die "$name: read $filename: $?\n";
+}
+
+exit 0;
diff --git a/scripts/lib.pl b/scripts/lib.pl
new file mode 100644 (file)
index 0000000..ba9c127
--- /dev/null
@@ -0,0 +1,565 @@
+# -*- perl -*-
+#
+# dpkg library: Debian GNU/Linux package maintenance utility,
+#  useful library functions.
+#
+# Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
+# Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+#   dpkg 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.
+#
+#   dpkg 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#   /var/lib/dpkg/ +---- status
+#                  |---- updates/ +---- <id>
+#                  |              |---- tmp.i
+#                  |              \---- <id>.new
+#                  |---- available
+#                  |---- lock
+#                  |---- info/ |---- <package>.{post,pre}{inst,rm}
+#                  |---- tmp.$$
+#                  \---- tmp.ci/ +---- control
+#                                |---- conffiles
+#                                |---- {post,pre}{inst,rm}
+#                                |---- list
+#                                \---- conffiles
+
+$backend = "dpkg-deb";
+$fpextract = "dpkg-deb";
+$md5sum = "md5sum";
+$dselect = "dselect";
+$dpkg = "dpkg";
+
+$status_mergeevery = 20;
+$tmp = "/tmp";
+$visiblecontroldir = "DEBIAN";
+
+sub setadmindir {
+    $dd = $_[0];
+    $statusdb    = "$dd/status";
+    $updatesdir  = "$dd/updates";
+    $availabledb = "$dd/available";
+    $scriptsdir  = "$dd/info";
+    $listsdir    = "$dd/info";
+    $lockfile    = "$dd/lock";
+    $lockmine    = "$dd/tmp.$$";
+    $controli    = "$dd/tmp.ci";
+    $importantspace = "$updatesdir/tmp.i";
+}
+$orgadmindir= "/var/lib/dpkg";
+&setadmindir($orgadmindir);
+
+@nokeepfields= ('package','version','package_revision',
+                'depends','recommended','optional','conflicts','part');
+# Don't keep these fields in the Available database if a new record is
+# merged which is missing values for any of them.
+    
+$packagere = '\w[-_a-zA-Z0-9+.@:=%]+';
+$packageversionre= $packagere.'(\s*\([^()]+\))?';
+$singledependencyre= "$packageversionre(\\s*\\|\\s*$packageversionre)*";
+
+# Abbreviations for dpkg-deb options common to dpkg & dpkg-deb.
+%debabbrevact= ('b','build', 'c','contents', 'e','control', 'i','info',
+                'f','field', 'x','extract', 'X','vextract');
+
+@keysortorder= ('package', 'status', 'version', 'package_revision',
+                'maintainer', 'description',
+                'depends', 'recommended', 'optional', 'conflicts',
+                'list', 'conffiles');
+    
+#*** replacements for things in headers ***#
+
+#require 'sys/errno.ph';
+sub ENOENT             { 2; }          # No such file or directory
+sub EEXIST             { 17; }         # File exists
+sub EISDIR             { 21; }         # Is a directory
+sub ENOTEMPTY          { 39; }         # Directory not empty
+
+#require 'sys/stat.ph';
+sub S_IFMT     { 00170000; }
+sub S_IFREG    { 0100000; }
+sub S_IFLNK    { 0120000; }
+sub S_ISREG    { ($_[0] & &S_IFMT) == &S_IFREG; }
+sub S_ISLNK    { ($_[0] & &S_IFMT) == &S_IFLNK; }
+
+#require 'sys/wait.ph';
+sub WIFEXITED { ($_[0] & 0x0ff) == 0; }
+sub WIFSTOPPED { ($_[0] & 0x0ff) == 0x07f; }
+sub WIFSIGNALED { !&WIFEXITED && !&WIFSTOPPED; }
+sub WCOREDUMP { ($_[0] & 0x080) != 0; }
+sub WEXITSTATUS { ($_[0] & 0x0ff00) >> 8; }
+sub WSTOPSIG { ($_[0] & 0x0ff00) >> 8; }
+sub WTERMSIG { $_[0] & 0x07f; }
+
+#require 'sys/signal.ph';
+sub SIGPIPE            { 13; }
+
+#require 'sys/syscall.ph';
+sub SYS_lseek          { 19; }
+
+
+#*** /var/lib/dpkg database management - `exported' routines ***#
+
+sub database_start {
+    # Lock the package management databases, amalgamate any
+    # changes files, and leave the results in:
+    #  From /var/lib/dpkg/status:
+    #   %st_pk2v{ package_name, field_name } = field_value
+    #   %st_p21{ package_name } = 1
+    #  From /var/lib/dpkg/available:
+    #   %av_pk2v{ package_name, field_name } = field_value
+    #   %av_p21{ package_name } = 1
+    #  From both:
+    #   %all_k21{ field_name } = 1
+    &lock_database;
+    &read_status_mainfile;
+    &read_status_extrafiles;
+    &write_status_mainfile;
+    &delete_status_extrafiles;
+    &read_available_file;
+    &prepare_important_database;
+    &invent_status_availableonly_packages;
+}
+
+sub database_finish {
+    # Tidy up and unlock the package management databases.
+    &release_important_database;
+    &write_available_file;
+    &write_status_mainfile;
+    &delete_status_extrafiles;
+    &unlock_database;
+}
+
+sub amended_status {
+    # Record amended status of package (in an `extra' file).
+    local (@packages) = @_;
+    local ($p);
+    &debug("amended @packages");
+    for $p (@packages) {
+        $st_pk2v{$p,'status'}= "$st_p2w{$p} $st_p2h{$p} $st_p2s{$p}";
+        $st_p21{$p}= 1;
+    }
+    $all_k21{'status'}= 1;
+    local ($ef) = sprintf("%03d",$next_extrafile++);
+    &write_database_file("$updatesdir/$ef",*st_pk2v,*st_p21,1,@packages);
+    push(@status_extrafiles_done,$ef); &sync;
+    if ($next_extrafile >= $status_mergeevery) {
+        &write_status_mainfile;
+        &delete_status_extrafiles;
+    }
+    $status_modified= 1;
+    for $p (@packages) { delete $st_pk2v{$p,'status'}; }
+    &prepare_important_database;
+}
+
+sub note_amended_status {
+    # Note the fact that the status has been modified, but don't
+    # commit yet.
+    $status_modified= 1;
+}
+
+sub amended_available {
+    # Record amended available information (in core for the moment -
+    # noncritical, so we defer writing it out).
+    $available_modified++;
+    &invent_status_availableonly_packages(@_);
+}
+
+#*** internal routines ***#
+
+sub invent_status_availableonly_packages {
+    local ($p);
+    for $p (@_ ? @_ : keys %av_p21) {
+        next if defined($st_p2w{$p});
+        $st_p2w{$p}= 'unknown';
+        $st_p2h{$p}= 'ok';
+        $st_p2s{$p}= 'not-installed';
+    }
+}
+
+sub read_status_mainfile {
+    local ($p, @p);
+    &read_status_database_file($statusdb);
+}
+
+sub read_status_extrafiles {
+    local ($fn);
+    opendir(UPD,$updatesdir) || &bombout("cannot opendir updates $updatesdir: $!");
+    for $_ (sort readdir(UPD)) {
+        next if $_ eq '.' || $_ eq '..';
+        if (m/\.new$/ || m/\.old$/ || $_ eq 'tmp.i') {
+            unlink("$updatesdir/$_") ||
+                &bombout("cannot unlink old update temp file $updatesdir/$_: $!");
+        } elsif (m/^\d+$/) {
+            $fn= $_;
+            &read_status_database_file("$updatesdir/$fn");
+            $status_modified= 1;  push(@status_extrafiles_done, $fn);
+        } else {
+            warn("$name: ignoring unexpected file in $updatesdir named \`$_'\n");
+        }
+    }
+    closedir(UPD);
+}
+
+sub read_status_database_file {
+    local ($filename) = @_;
+    @p= &read_database_file($filename,*st_pk2v,*st_p21);
+    for $p (@p) {
+        if (defined($st_pk2v{$p,'status'})) {
+            $v= $st_pk2v{$p,'status'};
+            $v =~ y/A-Z/a-z/;
+            $v =~
+                m/^(unknown|install|deinstall|purge)\s+(ok|hold)\s+(not-installed|unpacked|postinst-failed|installed|removal-failed|config-files)$/
+                    || &bombout("package \`$p' has bad status in $statusdb (\`$v')");
+            $st_p2w{$p}= $1;
+            $st_p2h{$p}= $2;
+            $st_p2s{$p}= $3;
+        }
+        delete($st_pk2v{$p,'status'});
+    }
+    $status_modified= 0; @status_extrafiles_done= ();
+}
+    
+sub write_status_mainfile {
+    return unless $status_modified;
+    local ($p);
+    for $p (keys %st_p21) {
+        $st_pk2v{$p,'status'}= "$st_p2w{$p} $st_p2h{$p} $st_p2s{$p}";
+    }
+    $all_k21{'status'}= 1;
+    unlink("$statusdb.old") || $!==&ENOENT ||
+        &bombout("unable to remove $statusdb.old: $!");
+    link("$statusdb","$statusdb.old") ||
+        &bombout("unable to back up $statusdb: $!");
+    &write_database_file($statusdb,*st_pk2v,*st_p21,0);
+    $status_modified= 0;
+    &sync;
+    for $p (keys %st_p21) { delete $st_pk2v{$p,'status'}; }
+}
+
+sub delete_status_extrafiles {
+#print STDERR "delete @status_extrafiles_done> "; <STDIN>;
+    for $_ (@status_extrafiles_done) {
+        unlink("$updatesdir/$_") ||
+            &bombout("cannot remove already-done update file $updatesdir/$_: $!");
+    }
+    $next_extrafile= 0;
+    @status_extrafiles_done= ();
+}
+
+sub read_available_file {
+    &read_database_file($availabledb,*av_pk2v,*av_p21);
+    $available_modified= 0;
+}
+
+sub write_available_file {
+    return unless $available_modified;
+    &write_database_file($availabledb,*av_pk2v,*av_p21,0);
+    $available_modified= 0;
+}
+
+#*** bottom level of read routines ***#
+
+sub read_database_file {
+    local ($filename, *xx_pk2v, *xx_p21) = @_;
+    local ($quick,$cf,@cf,%cf_k2v,@cwarnings,@cerrors,$p,@p)= 1;
+    &debug("reading database file $filename");
+    open(DB,"<$filename") || &bombout("unable to open $filename for reading: $!");
+    $/="";
+    @p=();
+    while (defined($cf=<DB>)) {
+        chop($cf);
+#       $cf =~ s/\n+$/\n/;
+        $p= &parse_control_entry;
+#        if (@cwarnings) {
+#            warn("$name: warning, packaging database file $filename\n".
+#                 " contains oddities in entry for package \`$p':\n  ".
+#                 join(";\n  ",@cwarnings).
+#                 ".\n This is probably a symptom of a bug.\n");
+#        }
+        if (@cerrors) {
+            &bombout("packaging database corruption - please report:\n".
+                     " file $filename has error(s) in entry for \`$p':\n  ".
+                     join(";\n  ",@cerrors). ".");
+        }
+        $xx_p21{$p}= 1;
+        for $k (keys %all_k21) { $xx_pk2v{$p,$k}= $cf_k2v{$k}; }
+        push(@p,$p);
+    }
+    &debug("database file $filename read");
+    $/="\n"; close(DB);
+    return @p;
+}
+
+sub parse_control_entry {
+    # Expects $cf to be a sequence of lines,
+    # representing exactly one package's information.
+    # Results are put in cf_k2v.
+    # @warnings and @errors are made to contain warning and error
+    # messages, respectively.
+    local ($ln,$k,$v,$p,$l);
+    @cwarnings= @cerrors= ();
+
+    undef %cf_k2v;
+#   &debug(">>>$cf<<<#\n");
+    if (!$quick) {
+        if ($cf =~ s/\n\n+/\n/g) { push(@cwarnings, "blank line(s) found and ignored"); }
+        if ($cf =~ s/^\n+//) { push(@cwarnings, "blank line(s) at start ignored"); }
+        if ($cf !~ m/\n$/) {
+            $cf.= "\n"; push(@cwarnings, "missing newline after last line assumed");
+        }    
+        if ($cf =~ s/\0//g) {
+            push(@cwarnings, "nul characters discarded");
+        }
+    }
+    $cf =~ s/\n([ \t])/\0$1/g; # join lines
+#   &debug(">>>$cf<<<*\n");
+    $ln = 0;
+    for $_ (split(/\n/,$cf)) {
+        $ln++; s/\s+$//;
+        next if m/^#/;
+        m/^(\S+):[ \t]*/ || (push(@cerrors, "garbage at line $ln, \`$_'"), next);
+        $k= $1; $v= $'; $k =~ y/A-Z/a-z/; $k='package_revision' if $k eq 'revision';
+#      &debug("key=\`$k' value=\`$v' line=\`$_'\n");
+        $ln += ($v =~ s/\0/\n/g);
+        $cf_k2v{$k}= $v;
+        $all_k21{$k}= 1;
+#     while ($cf =~ s/^(\S+):[ \t]*(.*)\n//) {
+    }
+    return unless keys %cf_k2v;
+    $p= $cf_k2v{'package'}; delete $cf_k2v{'package'}; delete $all_k21{'package'};
+    $cf_k2v{'class'} =~ y/A-Z/a-z/ if defined($cf_k2v{'class'});
+    $cf_k2v{'section'} =~ y/A-Z/a-z/ if defined($cf_k2v{'section'});
+#    length($cf) &&
+#        push(@cerrors, "garbage at line $ln, \`".($cf =~ m/\n/ ? $` : $cf)."'");
+    if (!$quick) {
+        defined($p) || push(@cerrors, "no \`package' line");
+        $p =~ m/^$packagere$/o || &bad_control_field('package');
+        defined($cf_k2v{'version'}) || push(@cerrors, "no Version field");
+        for $f ('depends','recommended','optional','conflicts') {
+            next unless defined($cf_k2v{$f}) && length($cf_k2v{$f});
+            $cf_k2v{$f} =~ m/^$singledependencyre(\s*,\s*$singledependencyre)*$/o
+                || &bad_control_field("$f");
+        }
+    }
+    return $p;
+}
+
+sub bad_control_field {
+    push(@cerrors, "bad \`$_[0]' line, contains \`$cf_k2v{$_[0]}'");
+}
+
+#*** bottom level of database writing code ***#
+
+sub write_database_file {
+    local ($filename, *xx_pk2v, *xx_p21, $important, @packages) = @_;
+    local ($p,$tl,$k,$v);
+    if (!@packages) { @packages= keys(%xx_p21); }
+
+    &debug("called write_database_file $filename, important=$important, for @packages");
+    if (!$important) {
+        open(DB,">$filename.new") || &bombout("unable to create $filename.new: $!");
+    }
+    $tl= 0;
+    for $p (@packages) {
+        &write_database_string("\n") if $tl;
+        &write_database_string("Package: $p\n");
+        for $k (keys %all_k21) {
+            next unless defined($xx_pk2v{$p,$k});
+            $v= $xx_pk2v{$p,$k};
+            $v =~ s/\n(\S)/\n $1/g;
+            &write_database_string("$k: $v\n");
+        }
+    }
+    if ($important) {
+        if (!truncate(IMP,$tl)) {
+            if (print(IMP "#")) {
+                warn("$name: warning - unable to truncate $importantspace: $!;".
+                     "\n commenting the rest out instead seems to have worked.\n");
+            } else {
+                &database_corrupted("unable to truncate $importantspace: $!");
+            }
+        }
+        close(IMP) || &database_corrupted("unable to close $importantspace: $!");
+        rename($importantspace,$filename) ||
+            &database_corrupted("unable to install $importantspace as $filename: $!");
+    } else {
+        close(DB) || &bombout("unable to close $filename.new: $!");
+        rename("$filename.new",$filename) ||
+            &bombout("unable to install $filename.new as $filename: $!");
+    }
+}
+
+sub write_database_string {
+    $tl += length($_[0]);
+    if ($important) {
+        print(IMP $_[0]) ||
+            &database_corrupted("failed write to update file $importantspace: $!");
+    } else {
+        print(DB $_[0]) ||
+            &bombout("failed to write to $filename.new: $!");
+    }
+}
+        
+sub database_corrupted {
+    &debug("corruptingstatus @_");
+    print STDERR "$name - really horrible error:\n @_\n".
+        "Package manager status data is now out of step with installed system.\n".
+        "(Last action has not been recorded.  Please try re-installing \`@packages'\n".
+        "to ensure system consistency, or seek assistance from an expert if\n".
+        "problems persist.)\n";
+    &cleanup; exit(2);
+}
+
+sub prepare_important_database {
+    open(IMP,"+>$importantspace") || &bombout("unable to create $importantspace: $!");
+    select((select(IMP),$|=1)[0]);
+    print(IMP "#padding\n"x512) || &bombout("unable to pad $importantspace: $!");
+    seek(IMP,0,0) || &bombout("unable to seek (rewind) $importantspace: $!");
+    &debug("important database prepared");
+}
+
+sub release_important_database {
+    close(IMP);
+    unlink($importantspace) || &bombout("unable to delete $importantspace: $!");
+    &debug("important database released");
+}
+
+#*** database lock management ***#
+
+sub lock_database {
+    # Lock the package management databases.  Stale locks will
+    # be broken, but there is no concurrency checking on the lock-
+    # breaking code.
+    push(@cleanups,'unlink($lockmine)');
+    open(PID,">$lockmine") || &bombout("failed to create new pid file $lockmine: $!");
+    printf(PID "%010d\n",$$) || &bombout("failed to add pid to $lockmine: $!");
+    close(PID) || &bombout("failed to close new pid file $lockmine: $!");
+    unless (link($lockmine,$lockfile)) {
+        $! == &EEXIST || &bombout("failed to create lock on packages database: $!");
+        if (open(PID,"<$lockfile")) {
+            undef $/; $opid= <PID>; $/="\n";
+            $opid =~ m/^\d{10}\n$/ || &lockfailed(" (pid missing)");
+            close(PID);
+            -d '/proc/self' ||
+                &bombout("/proc/self not found ($!) - /proc not mounted ?");
+            -d sprintf("/proc/%d",$opid) && &lockfailed(" (in use by pid $opid)");
+            if (open(PID,"<$lockfile")) {
+                $opid eq <PID> || &lockfailed(' (pid changed)');
+                close(PID);
+                unlink($lockfile) ||
+                    &bombout("failed to break stale lock on database: $!");
+                print STDERR
+                    "$name: stale lock found on packages database, lock forced\n";
+            } else {
+                $!==&ENOENT ||
+                    &bombout("failed to confirm who owns lock on database: $!");
+            }
+        } else {
+            $!==&ENOENT || &bombout("failed to determine who owns lock on database: $!");
+        }
+        link($lockmine,$lockfile) ||
+            &bombout("failed to create lock on packages database: $!");
+    }
+    push(@cleanups, 'unlink($lockfile) ||
+                     warn("$name: failed to unlock packages database: $!\n")');
+    unlink($lockmine);
+}
+
+sub unlock_database {
+    unlink($lockfile) || &bombout("failed to unlock packages database: $!");
+    pop(@cleanups);
+}
+
+#*** error handling ***#
+
+sub lockfailed  { &bombout("unable to lock packages database@_"); }
+sub bombout     { print STDERR "$name - critical error: @_\n"; &cleanup; exit(2); }
+sub badusage    { print STDERR "$name: @_\n\n"; &usage; &cleanup; exit(3); }
+
+sub outerr {
+    &bombout("failed write to stdout: $!");
+}
+
+sub cleanup {
+    while (@cleanups) {
+        eval(pop(@cleanups));
+        $@ && print STDERR "error while cleaning up: $@";
+    }
+}
+
+sub debug {
+    return unless $debug;
+    print "D: @_\n";
+}
+
+sub ecode {
+    local ($w,$s) = ($?,$!);
+    &debug("ecode $w syserr $s");
+    return
+#      (($w & 0x0ffff) == 0x0ff00 ? "problems running program - exit code -1" :
+#       ($w & 0x0ff) == 0 ? "exit status ".(($w & 0x0ff00) >> 8) :
+#       ($w & 0x0ff) == 0x07f ? "stopped by signal ".(($w & 0x0ff00) >> 8) : 
+#       "killed by signal ".($w & 0x07f).($w & 0x080 ? " (core dumped)" : '')).
+        (&WIFEXITED($w) ? "exit status ".&WEXITSTATUS($w) :
+         &WIFSIGNALED($w) ? "killed by signal ".&WTERMSIG($w).
+         (&WCOREDUMP($w) ? " (core dumped)" : ""):
+         &WIFSTOPPED($w) ? "stopped due to signal ".&WSTOPSIG($w) :
+         "unknown status $w").
+        ($s ? ", system error $s" : '');
+}
+
+#*** miscellaneous helpful routines ***#
+
+sub readall {
+    local ($fh) = @_;
+    local ($r,$n,$this) = '';
+    for (;;) {
+        defined($n=read($fh,$this,4096)) || return undef;
+        $n || last;
+        $r.= $this;
+    }
+    return $r;
+}
+
+#sub debug_compare_verrevs {
+#    local (@i)= @_;
+#    local ($i)= &x_compare_verrevs(@i);
+#    &debug("compare_verrevs >@i< = >$i<");
+#    return $i;
+#}
+
+sub compare_verrevs {
+    local ($av,$ar,$bv,$br,$c) = @_;
+    $c = &compare_vnumbers($av,$bv);  return $c if $c;
+    return &compare_vnumbers($ar,$br);
+}
+
+sub compare_vnumbers {
+    local ($a, $b) = @_;
+    do {
+        $a =~ s/^\D*//; $ad= $&; $ad =~ s/\W/ /g;
+        $b =~ s/^\D*//; $bd= $&; $bd =~ s/\W/ /g;
+        $cm = $ad cmp $bd; return $cm if $cm;
+        $a =~ s/^\d*//; $ad= $&;
+        $b =~ s/^\d*//; $bd= $&;
+        $cm = $ad <=> $bd; return $cm if $cm;
+    } while (length ($a) && length ($b));
+    return length ($a) cmp length ($b);
+}
+
+sub sync {
+    system('sync');
+}
diff --git a/scripts/perl-dpkg.pl b/scripts/perl-dpkg.pl
new file mode 100755 (executable)
index 0000000..ba70fc5
--- /dev/null
@@ -0,0 +1,1482 @@
+#!/usr/bin/perl --
+#
+# dpkg: Debian GNU/Linux package maintenance utility
+#
+# Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
+# Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+#   dpkg 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.
+#
+#   dpkg 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+$version= '0.93.15'; # This line modified by Makefile
+
+sub version {
+    print STDERR <<END;
+Debian GNU/Linux \`dpkg\' package handling tool version $version.
+Copyright (C)1994 Matt Welsh, Carl Streeter, Ian Murdock, Ian Jackson.
+This is free software; see the GNU General Public Licence version 2
+or later for copying conditions.  There is NO warranty.
+END
+}
+
+sub usage {
+    print STDERR <<END;
+Usage: dpkg -i|--install <opts> <.deb file name> ... | -a|--auto <dir> ...
+       dpkg --unpack     <opts> <.deb file name> ... | -a|--auto <dir> ...
+       dpkg -A|--avail   <opts> <.deb file name> ... | -a|--auto <dir> ...
+       dpkg --configure  <opts> <package name> ... | -a|--auto
+       dpkg -r|--remove  <opts> <package name> ... | -a|--auto
+       dpkg -l|--list   <status select> [<regexp> ...]
+       dpkg -s|--status <status select> [<package-name> ...]
+       dpkg -S|--search  <glob pattern> ...
+       dpkg -b|--build|-c|--contents|-e|--control|--info|-f|--field|
+            -x|--extract|-X|--vextract ...   (see dpkg-deb --help)
+Options:  --purge  --control-quiet --control-verbose  --version  --help
+          -R|--root=<directory>  --admindir=<directory>  --instdir=<directory>
+          --no-keep-old-conf  --no-keep-new-conf  -N|--no-also-select
+          --ignore-depends=<package name>,...
+          --conf-(same|diff|all)-(new|old|promptnew|promptold)
+          --force-<thing>,<thing>,...  --no-force-...|--refuse-...
+Status selections:   --isok-[o][h]        (OK, Hold; alternatives are y, n)
+                     --want-[u][i][d][p]  (Unknown, Install, Deinstall, Purge)
+ --stat-[nupircNO] (Not, Unpacked, Postinst-failed, Installed, Removal-failed,
+                    Config-files, Not/Config-files, Not/Config-files/Installed)
+Force things:  conflicts, depends, downgrade, depends-version, prermfail,
+               configure-any, hold, extractfail
+    (default is --no-force everything, except --force-downgrade)
+Use \`$dselect\' for user-friendly package management.
+END
+}
+
+$instroot= '';
+$controlwarn = 1;
+$estatus = 0;
+$filename_pattern = "*.deb";
+%force= ( 'conflicts',0, 'depends',0, 'depends-version',0, 'downgrade',1,
+          'prermfail',0, 'postrmfail',0, 'hold',0, 'configure-any',0,
+          'extractfail',0 );
+
+%selectmap_h= ('o','ok', 'h','hold', 'y','ok', 'n','hold');
+%selectmap_w= ('u', 'unknown', 'i', 'install', 'd', 'deinstall', 'p', 'purge');
+%selectmap_s= ('n', 'not-installed',
+               'u', 'unpacked',
+               'p', 'postinst-failed',
+               'i', 'installed',
+               'r', 'removal-failed',
+               'c', 'config-files',
+               'n', 'not-installed,config-files',
+               'o', 'not-installed,config-files,installed');
+%selectthings= ('isok','h', 'want','w', 'stat','s');
+
+require 'lib.pl'; # This line modified by Makefile
+$0 =~ m|[^/]+$|; $name = $dpkg;
+$|=1;
+umask(022);
+
+$action= 'none';
+
+%myabbrevact= ('i','install', 'r','remove', 'A','avail',
+               'S','search', 'l','list', 's','status');
+
+# $conf...[0] corresponds to `same', 1 to diff
+$confusenew[0]= 0;  $confprompt[0]= 0;
+$confusenew[1]= 1;  $confprompt[1]= 1;
+# Ie, default is to prompt only when hashes differ,
+# and to use new when hashes differ
+
+while ($ARGV[0] =~ m/^-/) {
+    $_= shift(@ARGV);
+    $noptsdone++;
+    if (m/^--$/) {
+        $noptsdone--; last;
+    } elsif (m/^--(install|remove|unpack|configure|avail|list|status)$/) {
+        &setaction($1);
+    } elsif (m/^--(build|contents|control|info|field|extract|vextract)$/) {
+        $noptsdone--; &backend($1);
+    } elsif (m/^--ignore-depends=($packagere(,$packagere)*)$/o) {
+        grep($ignore_depends{$_}=1, split(/,/,$1));
+    } elsif (m/^--(force|no-force|refuse)-/) {
+        $fvalue= ($1 eq 'force');
+        for $fv (split(/,/,$')) {
+            defined($force{$fv}) || &badusage("unknown --force option \`$fv'");
+            $force{$fv}= $fvalue;
+        }
+    } elsif (m/^--conf-(same|diff|all)-(new|old|promptnew|promptold)$/) {
+        $new= $2 eq 'new' || $2 eq 'promptnew';
+        $prompt= $2 eq 'promptnew' || $2 eq 'promptold';
+        if ($1 ne 'same') { $confusenew[1]= $new; $confprompt[1]= $prompt; }
+        if ($1 ne 'diff') { $confusenew[0]= $new; $confprompt[0]= $prompt; }
+    } elsif (m/^--(\w+)-(\w+)$/ && defined($selectthings{$1})) {
+        $thisname= $1;
+        $thisthing= $selectthings{$thisname};
+        $_=$2;
+        eval '%thismap= %selectmap_'.$thisthing;
+        while (s/^.//) {
+            if (!defined($thismap{$&})) {
+                &badusage("unknown status letter $& for status field $thisname");
+            }
+            $thiscodes= $thismap{$&};
+            $selectdo.= "undef \$select_$thisthing;";
+            for $v (split(m/,/, $thiscodes)) {
+                $selectdo .= "\$select_$thisthing{'$v'}=1;";
+            }
+        }
+    } elsif (m/^--root=/) {
+        $instroot=$'; &setadmindir("$instroot/$orgadmindir");
+    } elsif (m/^--admindir=/) {
+        &setadmindir("$'");
+    } elsif (m/^--instdir=/) {
+        $instroot=$';
+    } elsif (m/^--auto$/) {
+        $auto= 1;
+    } elsif (m/^--purge$/) {
+        $purge= 1;
+    } elsif (m/^--skip-same-version$/) {
+        print STDERR
+            "Warning: dpkg --skip-same-version not implemented, will process\n".
+            " process even packages the same version of which is installed.\n";
+    } elsif (m/^--no-also-select$/) {
+        $noalsoselect= 1;
+    } elsif (m/^--control-verbose$/) {
+        $controlwarn= 1;
+    } elsif (m/^--control-quiet$/) {
+        $controlwarn= 0;
+    } elsif (m/^--no-keep-old-conf$/) {
+        $nokeepold= 1;
+    } elsif (m/^--no-keep-new-conf$/) {
+        $nokeepnew= 1;
+    } elsif (m/^--succinct-prompts$/) {
+        $succinct= 1;
+    } elsif (m/^--debug$/) {
+        $debug= 1;
+    } elsif (m/^--help$/) {
+        &usage; exit(0);
+    } elsif (m/^--version$/) {
+        &version; exit(0);
+    } elsif (m/^--/) {
+        &badusage("unknown option \`$_'");
+    } else {
+        s/^-//; $noptsdone--;
+        while (s/^.//) {
+            $noptsdone++;
+            if (defined($myabbrevact{$&})) {
+                &setaction($myabbrevact{$&});
+            } elsif (defined($debabbrevact{$&})) {
+                $noptsdone--; &backend($debabbrevact{$&});
+            } elsif ($& eq 'a') {
+                $auto= 1;
+           } elsif ($& eq 'D') {
+               $debug= 1;
+           } elsif ($& eq 'N') {
+               $noautoselect= 1;
+            } elsif ($& eq 'R') {
+                s/^=// || &badusage("missing value for -R=<dir> option");
+                $instroot= $_; &setadmindir("$instroot/$orgadmindir"); $_='';
+            } else {
+                &badusage("unknown option \`-$&'");
+            }
+        }
+    }
+}
+
+$action eq 'none' && &badusage("an action must be specified");
+
+&debug("arguments parsed");
+
+#*** list, status or search - the nonactive operations ***#
+
+if ($action eq 'list' || $action eq 'status') {
+    &database_start;
+    if ($action eq 'list' || !@ARGV) {
+        &selectall(*selectmap_h,*select_h);
+        &selectall(*selectmap_w,*select_w);
+        &selectall(*selectmap_s,*select_s);
+        if (@ARGV) { $select_s{'not-installed'}=0; }
+    }
+    $ecode= 0;
+    if ($action eq 'status') {
+        for ($i=0;$i<=$#keysortorder;$i++) {
+            $keysortorder{$keysortorder[$i]}= sprintf("%6d ",$i);
+#           &debug("set $i: $keysortorder[$i], sortorder ".
+#                  "\`$keysortorder{$keysortorder[$i]}'");
+        }
+        @ARGV= &applyselcrit(sort keys %st_p21) unless @ARGV;
+        for $p (@ARGV) {
+            if (!$st_p21{$p}) {
+                print(STDERR "$name: no information available about package $p\n")
+                    || &bombout("writing to stderr: $!");
+                $ecode= 1;
+            }
+            print("Package: $p\n",
+                  "Status: $st_p2w{$p} $st_p2h{$p} $st_p2s{$p}\n") || &outerr;
+            for $k (sort { $keysortorder{$a}.$a cmp $keysortorder{$b}.$b; }
+                    keys %all_k21) {
+#               &debug("field $k, sortorder \`$keysortorder{$k}'");
+                next unless defined($st_pk2v{$p,$k});
+                $v= $st_pk2v{$p,$k}; next unless length($v);
+                if ($k eq 'conffiles' || $k eq 'list') {
+                    $v= sprintf("(%d files, not listed)",
+                                scalar(grep(m/\S/, split(/\n/,$v))));
+                }
+                print("$k: $v\n") || &outerr;
+            }
+            if (defined($av_p21{$p})) {
+                print("\n\`Available' version of package $p, where different:\n")
+                    || &outerr;
+                for $k (keys %all_k21) {
+                    next unless defined($av_pk2v{$p,$k});
+                    $v= $st_pk2v{$p,$k}; next unless length($v);
+                    $u= $st_pk2v{$p,$k}; next if $u eq $v;
+                    print("$k: $v\n") || &outerr;
+                }
+                print("\n") || &outerr;
+            }
+        }
+    } else { # $action eq 'list'
+        $listhead=0;
+        if (@ARGV) {
+            for $r (@ARGV) {
+                &listinfo(&applyselcrit(sort grep(m/$r/,keys %st_p21)));
+            }
+        } else {
+            undef $r;
+            &listinfo(&applyselcrit(sort keys %st_p21));
+        }
+    }
+    &database_finish;
+    exit($ecode);
+}
+
+sub listinfo {
+    if (!@_) {
+        print(STDERR
+              defined($r) ?
+              "No selected packages found matching regexp \`$r'.\n" :
+              "No packages matched selection criteria.\n") ||
+                  &bombout("writing to stderr: $!");
+        return;
+    }
+
+    if (!$listhead) {
+        print <<END
+Err?  Name       Version    Rev Description
+| Status=Not/Unpacked/Postinst-failed/Installed/Removal-failed/Config-files
+|/ Desired=Unknown/Install/Deinstall/Purge
+||/   |          |          |   |
++++-============-==========-===-===============================================
+END
+            || &outerr;
+        $listhead= 1;
+    }
+    for $p (@_) {
+        $des= $st_pk2v{$p,'description'};
+        $des= $` if $des =~ m/\n/;
+        printf("%s%.1s%.1s %-12.12s %-10.10s %-3.3s %-47.47s\n",
+               $st_p2h{$p} eq 'hold' ? 'x' : ' ', $st_p2s{$p}, $st_p2w{$p},
+               $p, $st_pk2v{$p,'version'}, $st_pk2v{$p,'package_revision'},
+               $des);
+    }
+}
+
+sub applyselcrit {
+    &debug("sel from @_");
+    for $f (@_) { &debug("$f :$st_p2s{$f},$select_s{$st_p2s{$f}}:$st_p2w{$f},$select_w{$st_p2w{$f}}:$st_p2h{$f},$select_h{$st_p2h{$f}}:"); }
+    @ascr= grep($select_s{$st_p2s{$_}} &&
+                $select_w{$st_p2w{$_}} &&
+                $select_h{$st_p2h{$_}},
+                @_);
+    &debug("sel gave @ascr");
+    @ascr;
+}
+
+sub selectall {
+    local (*map, *sel) = @_;
+    local ($v);
+    for $v (values %map) {
+        next if m/,/;
+        $sel{$v}=1;
+    }
+}
+
+if ($action eq 'search') {
+    @ARGV || &badusage("need at least one glob pattern for --$action");
+    &database_start;
+    while (@ARGV) {
+        $orgpat= $_= shift(@ARGV);
+        s/\W/\\$&/g;
+        s|\\\*\\\*|.*|g;
+        s|\\\*|[^/]*|g;
+        s|\\\?|[^/]|g;
+        $pat= $_; $f=0;
+        for $p (sort keys %st_p21) {
+            $s= $st_p2s{$p};
+            next if $s eq 'not-installed' || $s eq 'config-files';
+            &filesinpackage($arg, $package);
+            @ilist= grep(m/^$pat$/,@ilist);
+            next unless @ilist;
+            $f=1;
+            for $_ (@ilist) { print("$p: $_\n") || &outerr; }
+        }
+        if (!$f) {
+            print(STDERR "No packages found containing \`$orgpat'.\n")
+                || &bombout("writing to stderr: $!");
+            $ecode= 1;
+        }
+    }
+    &database_finish;
+    exit($ecode);
+}
+
+#*** lock and read in databases ***#
+
+&database_start;
+&debug("databases read");
+
+#*** derive argument list for --auto ***#
+
+if ($auto) {
+    if ($action eq 'install' || $action eq 'unpack' || $action eq 'avail') {
+        @ARGV || &badusage("need at least one directory for --$action --auto");
+        pipe(RP,WP) || &bombout("create pipe for \`find': $!");
+        defined($c= fork) || &bombout("fork for \`find': $!");
+        if (!$c) {
+            close(RP); open(STDOUT,">& WP"); close(WP);
+            exec('find',@ARGV,'-name',$filename_pattern,'-type','f','-print0');
+            die "$name: could not exec \`find': $!";
+        }
+        close(WP);
+        $/="\0"; @ARGV= <RP>; $/="\n";
+        eof || &bombout("read filenames from \`find': $!");
+        close(RP);
+        $!=0; waitpid($c,0) eq $c || &bombout("wait for \`find' failed: $!");
+        $? && &bombout("\`find' process returned error code ".&ecode);
+        @ARGV || &bombout("no packages found to $action");
+    } else {
+        @ARGV && &badusage("no package names may be specified with --$action --auto");
+        if ($action eq 'remove') {
+            eval 'sub condition {
+                $wants eq "deinstall" || $wants eq "purge" || return 0;
+                $cstatus eq "not-installed" && return 0;
+                $cstatus eq "config-files" && $wants eq "deinstall" && return 0;
+                return 1;
+            } 1;' || &internalerr("sub condition: $@");
+        } elsif ($action eq 'configure') {
+            eval 'sub condition {
+                $wants eq "install" || return 0;
+                $cstatus eq "unpacked" || $cstatus eq "postinst-failed" || return 0;
+                return 1;
+            } 1;' || &internalerr("sub condition: $@");
+        } else {
+            &internalerr("unknown auto nonames action $action");
+        }
+        for $p (keys %st_p21) {
+            next if $st_p2h{$p} eq 'hold';
+            $wants= $st_p2w{$p}; $cstatus= $st_p2s{$p};
+            next unless &condition;
+            push(@ARGV,$p);
+        }
+    }
+    &debug("auto: arglist @ARGV");
+} else {
+    @ARGV || &badusage("need a list of packages or filenames");
+}
+
+if ($action eq 'install' || $action eq 'unpack') {
+    grep(s:^[^/.]:./$&:, @ARGV); # Sanitise filenames
+}
+
+&debug("action: $action; arglist @ARGV");
+
+#*** actually do things ***#
+
+for $arg (@ARGV) {
+    $package= ''; @undo=();
+    &debug("&do_$action($arg)");
+    if (!eval "&do_$action(\$arg); 1;") { &handleerror || last; }
+    &checkpointstatus;
+}
+&checkpointstatus;
+
+if (!$abort) {
+    &debug("&middle_$action($arg)");
+    if (!eval "&middle_$action; 1;") { print STDERR $@; $abort=1; }
+}
+&checkpointstatus;
+
+if (!$abort) {
+    while (@deferred) {
+        $arg= shift(@deferred); $package= ''; @undo=();
+       &debug("&deferred_$action($arg) ($dependtry: $sincenothing)");
+        if (!eval "&deferred_$action(\$arg); 1;") { &handleerror || last; }
+        &checkpointstatus;
+    }
+    &checkpointstatus;
+}
+
+if ($errors) {
+    print STDERR "$name: $errors errors occurred.\n";
+    $estatus= 1;
+}
+
+&database_finish;
+&cleanup;
+
+exit($estatus);
+
+#*** useful subroutines for main control section ***#
+
+sub handleerror {
+    print STDERR $@;
+    if (length($package) && defined($st_p21{$package})) {
+        $st_p2h{$package}='hold'; &amended_status($package);
+    }
+    $errors++;
+    if ($errors >20) { print STDERR "$name: too many errors, halting\n"; return 0; }
+    return !$abort;
+}
+
+sub checkpointstatus {
+    return unless keys %statusupdated;
+    &amended_status(keys %statusupdated);
+    undef %statusupdated;
+}
+
+sub backend {
+    &setaction('');
+    ($noptsdone) && &badusage("action \`$_[0]' must be first argument");
+    &debug("backend --$_[0]");
+    exec($backend, "--$_[0]", @ARGV);
+    &bombout("unable to run $backend: $!");
+}
+
+sub setaction {
+    $action eq 'none' || &badusage("conflicting actions \`$action' and \`$1'");
+    $action= $_[0];
+}
+
+#*** error handlers for use in actions ***#
+
+sub warn        { warn "$name - warning: @_\n"; }
+sub subcriterr  { warn "$name - subcritical error: @_\n"; $estatus=1; }
+sub error       { &acleanup; die "$name - error: @_\n"; }
+sub internalerr { &acleanup; die "$name - internal error, please report: @_\n"; }
+sub fatalerr    { &acleanup; die "$name - fatal error, halting: @_\n"; $abort=1; }
+
+sub corruptingerr {
+    local ($corruptingerr)= @_;
+    &acleanup;
+    die "$name - horrible error: $corruptingerr;\n".
+        "Package manager data is now out of step with installed system.\n".
+        "Please re-install \`$package' to ensure system consistency!\n".
+        "(Seek assistance from an expert if problems persist.)\n";
+    $abort=1;
+}
+
+sub forcibleerr {
+    local ($msg,@forces) = @_;
+    if (@forces= grep($force{$_},@forces)) {
+        &warn("$msg (proceeding due to --force-$forces[0])");
+    } else {
+        &error("$msg (skipping this package)");
+    }
+}
+
+sub acleanup {
+    while (@undo) {
+        eval(pop(@undo));
+        $@ && print STDERR "error while cleaning up: $@";
+    }
+}
+
+#*** --install ***#
+
+sub do_install {
+    &do_unpack($arg);
+    $arg= $package;
+    &do_configure($arg);
+}
+
+sub deferred_install { &deferred_configure; }
+
+sub middle_install { &middle_configure }
+
+#*** --avail ***#
+
+sub do_avail {
+    unlink($controli);
+    if ($! != &ENOENT) {
+        system('rm','-rf',$controli);
+        unlink($controli);
+        $! == &ENOENT || &fatalerr("unable to get rid of $controli: $!");
+    }
+    &debug("extract control $backend --control $arg $controli");
+    $!=0; system($backend,"--control",$arg,$controli);
+    $? && &error("$arg: could not extract control information (".&ecode.")");
+    open(CONTROL,"$controli/control") ||
+        &error("$arg: corrupt - unable to read control file: $!");
+    &parse_control("$arg");
+    for $k (keys %cf_k2v) {
+        $av_pk2v{$p,$k}= $cf_k2v{$k};
+    }
+    for $k (@nokeepfields) {
+        delete $av_pk2v{$p,$k} unless defined($cf_k2v{$k});
+    }
+    &amended_available($p);
+    $package=$p;
+}
+
+sub deferred_avail { }
+sub middle_avail { }
+
+#*** --unpack ***#
+
+sub middle_unpack { }
+
+sub do_unpack {
+    &do_avail;
+    $cstatus= $st_p2s{$package};
+    if ($st_p2w{$package} ne 'install') {
+        if (!$noalsoselect) {
+            $st_p2w{$package}= 'install'; $statusupdated{$package}= 1;
+            print STDOUT "Selecting previously deselected package $package.\n";
+        } else {
+            print STDOUT "Skipping deselected package $package.\n";
+            return;
+        }
+    }
+    for $tp (split(/,/, $av_pk2v{$package,'conflicts'})) {
+       $tp =~ s/^\s*//; $tp =~ s/\s+$//;
+        ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
+        unless ($tps eq 'not-installed' || $tps eq 'config-files' || !$rightver) {
+            &forcibleerr("$arg: conflicts with package $tpp ($want),".
+                         " found $inst on system",
+                         'conflicts');
+        }
+    }
+    if ($cstatus eq 'installed') {
+        if (&compare_verrevs($av_pk2v{$package,'version'},
+                             $av_pk2v{$package,'package_revision'},
+                             $st_k2v{'version'},$st_k2v{'package_revision'}) <0) {
+            &forcibleerr("$arg: downgrading installed $package version ".
+                         "$st_k2v{'version'}, ".
+                         "package revision $st_k2v{'package_revision'} ".
+                         "to older version ".
+                         "$av_pk2v{$package,'version'}, ".
+                         "package revision $av_pk2v{$package,'package_revision'}",
+                         'downgrade');
+        }
+    }
+    if (open(CONF,"$controli/conffiles")) {
+        @configf= <CONF>;
+        eof || &error("$arg: unable to read $controli/conffiles: $!");
+        close(CONF);
+        grep((chop, m,^/, || s,^,/,), @configf);
+    } elsif ($! != &ENOENT) {
+        &error("$arg: cannot get config files list: $!");
+    } else {
+        @configf= ();
+    }
+
+    if ($cstatus eq 'installed' || $cstatus eq 'unpacked' ||
+        $cstatus eq 'postinst-failed' || $cstatus eq 'removal-failed') {
+        &filesinpackage($arg,$package);
+        print STDOUT "Preparing to replace $package ...\n";
+    }
+    if ($cstatus eq 'installed') {
+        if (!eval {
+            &run_script_ne("$scriptsdir/$package.prerm", 'old pre-removal script',
+                          'upgrade',
+                           $av_pk2v{$package,'version'}.'-'.
+                           $av_pk2v{$package,'package_revision'});
+            1;
+        }) {
+            &warn("$@... trying script from new package instead.");
+            &run_script("$controli/prerm", 'new prerm script',
+                       'failed-upgrade',
+                        $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
+        }
+        push(@undo,
+             '$st_p2s{$package}= "postinst-failed"; $statusupdated{$package}=1;
+             &run_script_ne("$scriptsdir/$package.postinst",
+                            "old post-installation script",
+                            "abort-upgrade",
+                            $av_pk2v{$package,"version"}."-".
+                            $av_pk2v{$package,"package_revision"});
+             $st_p2s{$package}= "installed"; $statusupdated{$package}=1;');
+    }
+    @fbackups=();
+    if ($cstatus eq 'installed' || $cstatus eq 'unpacked' ||
+        $cstatus eq 'postinst-failed' || $cstatus eq 'removal-failed') {
+        for ($i=0; $i<=$#ilist; $i++) {
+            next if grep($_ eq $ilist[$i], @configf);
+            $_= $ilist[$i];
+            unless (lstat("$instroot/$_")) {
+                $! == &ENOENT || &error("old file $_ unstattable: $!");
+                next;
+            }
+            next if -d _;
+            rename("$instroot/$_","$instroot/$_.dpkg-tmp") ||
+                &error("couldn't rename old file $_ to $_.dpkg-tmp: $!");
+            push(@undo,
+                 '$_=pop(@fbackups); rename("$instroot/$_.dpkg-tmp","$instroot/$_") ||
+                  die "unable to undo rename of $_ to $_.dpkg-tmp: $!"');
+            push(@fbackups, $_);
+        }
+        if (!eval {
+            &run_script_ne("$scriptsdir/$package.postrm", 'old post-removal script',
+                          'upgrade',
+                           $av_pk2v{$package,'version'}.'-'.
+                           $av_pk2v{$package,'package_revision'});
+            1;
+        }) {
+            &warn("$@... trying script from new package instead.");
+            &run_script("$controli/postrm", 'new post-removal script',
+                       'failed-upgrade',
+                        $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
+        }
+        push(@undo,
+             '&run_script_ne("$scriptsdir/$package.preinst",
+                             "old pre-installation script",
+                             "abort-upgrade",
+                             $av_pk2v{$package,"version"}.
+                             "-".$av_pk2v{$package,"package_revision"})');
+    }
+    $shortarg= $arg; $shortarg =~ s:.{15,}/:.../:;
+    print STDOUT "Unpacking $arg, containing $package ...\n";
+    &run_script("$controli/preinst", 'pre-installation script',
+               'upgrade', $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
+    push(@undo,'&run_script_ne("$controli/postrm", "post-removal script",
+                               "abort-upgrade",
+                               $st_k2v{"version"}."-".$st_k2v{"package_revision"})');
+    if ($cstatus ne 'not-installed') {
+        for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
+            s/^ //; next unless length($_);
+            if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
+                &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
+                next;
+            }
+            $oldhash{$1}= $2;
+        }
+    }
+    for $f (@configf) {
+        $drf= &conffderef($f); if (!defined($drf)) { next; }
+        if (lstat("$instroot/$drf.dpkg-tmp")) {
+            $undo=1;
+        } else {
+            $! == &ENOENT || &error("unable to stat backup config file $_.dpkg-tmp: $!");
+            if (lstat("$instroot/$drf")) {
+                rename("$instroot/$drf","$instroot/$drf.dpkg-tmp") ||
+                    &error("couldn't back up config file $f (= $drf): $!");
+                $undo=1;
+            } elsif ($! == &ENOENT) {
+                $undo=0;
+            } else {
+                &error("unable to stat config file $drf: $!");
+            }
+        }
+        if ($undo) {
+            push(@undo,
+                 '$_=pop(@undof); rename("$instroot/$_.dpkg-tmp","$instroot/$_") ||
+                 die "unable to undo backup of config file $_: $!"');
+            push(@undof, $drf);
+        }
+    }
+
+    open(NL,">$listsdir/$package.list.new") ||
+        &error("$package: cannot create $listsdir/$package.list.new: $!");
+    defined($c= fork) || &error("$package: cannot pipe/fork for $backend --vextract");
+    if (!$c) {
+        if (!open(STDOUT,">&NL")) {
+            print STDERR "$name: cannot redirect stdout: $!\n"; exit(1);
+        }
+        $vexroot= length($instroot) ? $instroot : '/';
+        exec($backend,"--vextract",$arg,$vexroot);
+        print STDERR "$name: cannot exec $backend --vextract $arg $vexroot: $!\n";
+        exit(1);
+    }
+    $!=0; waitpid($c,0) == $c || &error("could not wait for $backend: $!");
+    $? && &forcibleerr("$package: failed to install (".&ecode.")", 'extractfail');
+
+    rename("$listsdir/$package.list.new","$listsdir/$package.list") ||
+        &error("$package: failed to install new $listsdir/$package.list: $!");
+    
+    $newconff='';
+    for $f (@configf) {
+        $h= $oldhash{$f};
+        $h='newconffile' unless length($h);
+        $newconff.= "\n $f $h";
+        &debug("new hash, after unpack, of $f, is $h");
+    }
+
+    for $k (keys %all_k21) {
+        next if $k eq 'binary' || $k eq 'source' || $k eq 'section';
+        $st_pk2v{$package,$k}= $av_pk2v{$package,$k};
+    }
+    $st_pk2v{$package,'conffiles'}= $newconff; $all_k21{'conffiles'}= 1;
+    $st_p2s{$package}= 'unpacked'; $st_p2h{$package}= 'ok'; $st_p21{$package}= 1;
+    $statusupdated{$package}= 1;
+    @undo=(); @undof=();
+
+    for $f (@fbackups) {
+        unlink("$instroot/$f.dpkg-tmp") || $! == &ENOENT ||
+            &subcriterr("$package: unable to delete saved old file $f.dpkg-tmp: $!\n");
+    }
+
+    undef %fordeletion;
+    opendir(PI,"$scriptsdir") ||
+        &corruptingerr("$package: unable to read $scriptsdir directory ($!)");
+    while(defined($_=readdir(PI))) {
+        next unless substr($_,0,length($package)+1) eq $package.'.';
+        $fordeletion{$_}= 1;
+    }
+    closedir(PI);
+    opendir(PI,"$controli") ||
+        &corruptingerr("$package: unable to read $controli".
+                       " new package control information directory ($!)");
+    $fordeletion{"$package.list"}= 0;
+    while(defined($_=readdir(PI))) {
+        next if m/^\.\.?$/ || m/^conffiles$/ || m/^control$/;
+        rename("$controli/$_","$scriptsdir/$package.$_") ||
+            &corruptingerr("$package: unable to install new package control".
+                           " information file $scriptsdir/$package.$_ ($!)");
+        $fordeletion{"$package.$_"}= 0;
+    }
+    closedir(PI);
+    for $_ (keys %fordeletion) {
+        next unless $fordeletion{$_};
+        unlink("$scriptsdir/$_") ||
+            &corruptingerr("$package: unable to remove old package script".
+                           " $scriptsdir/$_ ($!)");
+    }
+}
+
+#*** --configure ***#
+
+sub do_configure {
+    $package=$arg; $cstatus= $st_p2s{$package};
+    if (!defined($st_p21{$package})) { $cstatus= 'not-installed'; }
+    unless ($cstatus eq 'unpacked' || $cstatus eq 'postinst-failed') {
+        if ($cstatus eq 'not-installed') {
+            &error("no package named \`$package' is installed, cannot configure");
+        } else {
+            &error("$package: is currently in state \`$cstatus', cannot configure");
+        }
+    }
+    push(@deferred,$package);
+}
+
+sub middle_configure {
+    $sincenothing=0; $dependtry=1;
+}
+
+sub deferred_configure {
+    # The algorithm for deciding what to configure first is as follows:
+    # Loop through all packages doing a `try 1' until we've been round
+    # and nothing has been done, then do `try 2' and `try 3' likewise.
+    # Try 1:
+    #  Are all dependencies of this package done ?  If so, do it.
+    #  Are any of the dependencies missing or the wrong version ?
+    #   If so, abort (unless --force-depends, in which case defer)
+    #  Will we need to configure a package we weren't given as an
+    #   argument ?  If so, abort - except if --force-configure-any,
+    #   in which case we add the package to the argument list.
+    #  If none of the above, defer the package.
+    # Try 2:
+    #  Find a cycle and break it (see above).
+    #  Do as for try 1.
+    # Try 3 (only if --force-depends-version).
+    #  Same as for try 2, but don't mind version number in dependencies.
+    # Try 4 (only if --force-depends).
+    #  Do anyway.
+    $package= $arg;
+    if ($sincenothing++ > $#deferred*2+2) {
+        $dependtry++; $sincenothing=0;
+        &internalerr("$package: nothing configured, but try was already 4 !")
+            if $dependtry > 4;
+    }
+    if ($dependtry > 1) { &findbreakcycle($package); }
+    ($ok, @aemsgs) = &dependencies_ok($package,'');
+    if ($ok == 1) {
+        push(@deferred,$package); return;
+    } elsif ($ok == 0) {
+        $sincenothing= 0;
+        &error("$arg: dependency problems - not configuring this package:\n ".
+               join("\n ",@aemsgs));
+    } elsif (@aemsgs) {
+        &warn("$arg: dependency problems, configuring anyway as you request:\n ".
+              join("\n ",@aemsgs));
+    }
+    $sincenothing= 0;
+    print STDOUT "Setting up $package ...\n";
+    if ($st_p2s{$package} eq 'unpacked') {
+        &debug("conffiles updating >$st_pk2v{$package,'conffiles'}<");
+        undef %oldhash; @configf=();
+        for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
+            s/^ //; next unless length($_);
+            if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
+                &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
+                next;
+            }
+            $oldhash{$1}= $2; push(@configf,$1);
+            &debug("old hash of $1 is $2");
+        }
+        undef %newhash;
+        for $file (@configf) {
+            $drf= &conffderef($file);
+            if (!defined($drf)) { $newhash{$file}= '-'; next; }
+            $newhash{$file}= &hash("$instroot/$drf");
+            &debug("new hash of $file is $newhash{$file} (old $oldhash{$file})");
+            if ($oldhash{$file} eq 'newconffile') {
+                $usenew= 1;
+            } else {
+                if (!&files_not_identical("$instroot/$drf",
+                                          "$instroot/$drf.dpkg-tmp")) {
+                    rename("$instroot/$drf.dpkg-tmp",$drf) || $!==&ENOENT ||
+                        &error("$package: unable to reinstall ".
+                               "existing conffile $drf.dpkg-tmp: $!");
+                    &debug("files identical $file");
+                } else {
+                    $diff= $newhash{$file} ne $oldhash{$file};
+                    $usenew= $confusenew[$diff];
+                    &debug("the decision - diff $diff;".
+                           " usenew $usenew prompt $confpromt[$diff]");
+                    if ($confprompt[$diff]) {
+                        $symlinked = $drf eq $file ? '' :
+                            $succinct ? " (-> $drf)" :
+                                " (which is a symlink to $drf)";
+                        for (;;) {
+                            print
+                                $succinct ? "
+Package $package, file $file$symlinked, ".($diff ? "CHANGED": "not changed")
+                                  : $diff ? "
+In package $package, distributed version of configuration
+file $file$symlinked has changed
+since the last time it was installed.  You may:
+ * Install the new version and edit it later to reflect your wishes.
+   ". ($nokeepold ?
+  "(Your old version will not be saved.)" :
+  "(Your old version will be saved in $drf.dpkg-old.)") . "
+ * Leave your old version in place, and perhaps check later that
+   you don't want to update it to take account of new features.
+   ". ($nokeepnew ?
+  "(The new version be discarded.)" :
+  "(The new version will be placed in $drf.dpkg-new.)")
+                                          : "
+Package $package contains the same distributed version of
+configuration file $file$symlinked
+as the last time it was installed.  You may:
+ * Install the distributed version, overwriting your changes.
+   ". ($nokeepold ?
+  "(Your changed version will not be saved.)" :
+  "(Your changed version will be saved in $drf.dpkg-old.)") . "
+ * Leave your own version in place.
+   ". ($nokeepnew ?
+  "(The distributed version be discarded.)" :
+  "(The distributed version will be placed in $drf.dpkg-new.)");
+
+                            print "
+$file: install new version ? (y/n, default=". ($usenew?'y':'n'). ")  ";
+
+                            $!=0; defined($iread= <STDIN>) ||
+                                &error("$package: prompting, EOF/error on stdin: $!");
+                            $_= $iread; s/^\s*//; s/\s+$//;
+                            ($usenew=0, last) if m/^n(o)?$/i;
+                            ($usenew=1, last) if m/^y(es)?$/i;
+                            last if m/^$/;
+                            print "\nPlease answer \`y' or \`n'.\n";
+                        }
+                    }
+                    &debug("decided, usenew $usenew");
+                    if ($usenew) {
+                        &copyperm("$drf.dpkg-tmp",$drf,$drf);
+                        if ($nokeepold) {
+                            unlink("$instroot/$drf.dpkg-tmp") || $!==&ENOENT ||
+                                &error("$package: unable to delete old conffile ".
+                                       "$drf.dpkg-tmp: $!");
+                            unlink("$instroot/$drf.dpkg-old") || $!==&ENOENT ||
+                                &error("$package: unable to delete very old ".
+                                       "conffile $drf.dpkg-old: $!");
+                        } else {
+                            rename("$instroot/$drf.dpkg-tmp","$instroot/$drf.dpkg-old")
+                                || $!==&ENOENT ||
+                                    &error("$package: unable to back up old conffile ".
+                                           "$drf.dpkg-tmp as $drf.dpkg-old: $!");
+                        }
+                    } else {
+                        unlink("$instroot/$drf.dpkg-new") || $!==&ENOENT ||
+                            &error("$package: unable to delete old new conffile ".
+                                   "$drf.dpkg-new: $!");
+                        if (!$nokeepnew) {
+                            link("$instroot/$drf","$instroot/$drf.dpkg-new")
+                                || $!==&ENOENT ||
+                                    &error("$package: unable save new conffile ".
+                                           "$drf as $drf.dpkg-new: $!");
+                        }
+                        if (!rename("$instroot/$drf.dpkg-tmp","$instroot/$drf")) {
+                            $!==&ENOENT || &error("$package: unable reinstall old ".
+                                                  "conffile $drf.dpkg-tmp as $drf: $!");
+                            unlink("$instroot/$drf");
+                        }
+                    }
+                }
+            }
+        }
+        $newconff='';
+        for $f (@configf) {
+            $h= $newhash{$f}; $newconff.= "\n $f $h";
+        }
+        $st_pk2v{$package,'conffiles'}= $newconff; $all_k21{'conffiles'}= 1;
+    }
+    $st_p2s{$package}= 'postinst-failed'; $statusupdated{$package}= 1;
+    &run_script("$scriptsdir/$package.postinst",
+                'post-installation script', 'configure');
+    $st_p2s{$package}= 'installed';
+    $st_p2h{$package}= 'ok'; $statusupdated{$package}= 1;
+}
+
+#*** --remove ***#
+
+sub do_remove {
+    $package=$arg; $cstatus= $st_p2s{$package};
+    if (!defined($st_p21{$package}) ||
+        $cstatus eq 'not-installed' ||
+        !$purge && $cstatus eq 'config-files') {
+        &error("$package: is not installed, cannot remove");
+    }
+    push(@deferred,$package);
+    if (!$auto) {
+        $ns= $purge ? 'purge' : 'deinstall';
+        if ($st_p2w{$package} ne $ns) {
+            $st_p2w{$package}= $ns; $statusupdated{$package}= 1;
+        }
+    }
+}
+
+sub middle_remove {
+    $sincenothing=0; $dependtry=1;
+    for $p (keys %st_p2s) {
+        $cstatus= $st_p2s{$p};
+        next unless $cstatus eq 'installed';
+        for $tp (split(/[\|,]/, $st_pk2v{$p,'depends'})) {
+            $tp =~ s/\s*\(.+\)\s*$//; $tp =~ s/^\s*//; $tp =~ s/\s+$//;
+            $tp =~ m/^$packagere$/o ||
+                &internalerr("package $p dependency $tp didn't match re");
+            $depended{$tp}.= "$p ";
+        }
+    }
+}
+
+sub deferred_remove {
+    $package= $arg;
+    if ($sincenothing++ > $#deferred*2+2) {
+        $dependtry++; $sincenothing=0;
+        &internalerr("$package: nothing configured, but try was already 4 !")
+            if $dependtry > 4;
+    }
+    @raemsgs= (); $rok= 2;
+    &debug("$package may be depended on by any of >$depended{$package}<");
+    for $fp (split(/ /, $depended{$package})) {
+        next if $fp eq '' || $ignore_depends{$tp};
+       $is= $st_p2s{$fp};
+       next if $is eq 'not-installed' || $is eq 'unpacked' ||
+               $is eq 'removal-failed' || $is eq 'config-files';
+       if ($dependtry > 1) { &findbreakcycle($fp); }
+        ($ok, @aemsgs) = &dependencies_ok($fp,$package);
+        if ($rok != 1) { push(@raemsgs,@aemsgs); }
+        $rok= $ok if $ok < $rok;
+    }
+    if ($rok == 1) {
+        push(@deferred,$package); return;
+    } elsif ($rok == 0) {
+        $sincenothing= 0;
+        &error("$arg: dependency problems - not removing this package:\n ".
+               join("\n ",@raemsgs));
+    } elsif (@raemsgs) {
+        &warn("$arg: dependency problems, removing anyway as you request:\n ".
+              join("\n ",@raemsgs));
+    }
+    $sincenothing= 0;
+    &filesinpackage($arg,$package);
+
+    undef %hash; @configfr= @configf= ();
+    for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
+        s/^ //; next unless length($_);
+        if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
+            &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
+            next;
+        }
+        unshift(@configfr,$1); push(@configf,$1);
+        $hash{$1}= $2;
+    }
+    
+    if ($st_p2s{$package} ne 'config-files') {
+       print STDOUT "Removing $package ...\n";
+        &run_script("$scriptsdir/$package.prerm", 'pre-removal script', 'remove');
+        $st_p2s{$package}= 'removal-failed'; $statusupdated{$package}= 1;
+        for $file (reverse @ilist) {
+            next if grep($_ eq $file, @configf);
+            unlink("$instroot/$file.dpkg-tmp") || $! == &ENOENT ||
+                &error("$arg: cannot remove supposed old temp file $file: $!");
+            next if unlink("$instroot/$file");
+            next if $! == &ENOENT;
+            &error("$arg: cannot remove file $file: $!") unless $! == &EISDIR;
+            next if rmdir("$instroot/$file");
+            &error("$arg: cannot remove directory $file: $!") unless $! == &ENOTEMPTY;
+        }
+        &run_script("$scriptsdir/$package.postrm", 'post-removal script', 'remove');
+        opendir(DSD,"$scriptsdir") ||
+            &error("$arg: cannot read directory $scriptsdir: $!");
+        for $_ (readdir(DSD)) {
+            next unless m/\.[^.]$/;
+            next if $& eq '.postrm' || $& eq '.list';
+            # need postrm for --purge, and list has to go last in case it
+            # goes wrong
+            next unless $` eq $package;
+            unlink("$scriptsdir/$_") ||
+                &error("$arg: unable to delete control information $scriptsdir/$_: $!");
+        }
+        closedir(DSD);
+        $st_p2s{$package}= 'config-files';
+        $statusupdated{$package}= 1;
+    }
+    if ($purge) {
+       print STDOUT "Purging configuration files for $package ...\n";
+        push(@undo,
+             '$newconff="";
+             for $f (@configf) { $newconff.= "\n $f $hash{$f}"; }
+             $st_pk2v{$package,"conffiles"}= $newconff; $all_k21{"conffiles"}= 1;');
+        for $file (@configfr) {
+            $drf= &conffderef($file); if (!defined($drf)) { next; }
+            unlink("$instroot/$drf") || $! == &ENOENT ||
+                &error("$arg: cannot remove old config file $file (= $drf): $!");
+            $hash{$file}= 'newconffile';
+            unlink("$instroot/$file") || $! == &ENOENT ||
+                &error("$arg: cannot remove old config file $file: $!")
+                    if $file ne $drf;
+            for $ext ('.dpkg-tmp', '.dpkg-old', '.dpkg-new', '~', '.bak', '%') {
+                unlink("$instroot/$drf$ext") || $! == &ENOENT ||
+                    &error("$arg: cannot remove old config file $drf$ext: $!");
+            }
+            unlink("#$instroot/$drf#") || $! == &ENOENT ||
+                &error("$arg: cannot remove old auto-save file #$drf#: $!");
+            $drf =~ m,^(.*)/, || next; $dir= $1; $base= $';
+            if (opendir(CFD,"$instroot/$dir")) {
+                for $_ (readdir(CFD)) {
+                    next unless m/\.~\d+~$/;
+                    next unless $` eq $base;
+                    unlink("$instroot/$dir/$_") || $! == &ENOENT ||
+                        &error("$arg: cannot remove old emacs backup file $dir/$_: $!");
+                }
+                closedir(CFD);
+                if (grep($_ eq $dir, @ilist)) {
+                    rmdir("$instroot/$dir") || $! == &ENOTEMPTY ||
+                        &error("$arg: cannot remove config file directory $dir: $!");
+                }
+            } elsif ($! != &ENOENT) {
+                &error("$arg: cannot read config file dir $dir: $!");
+            }
+        }
+       &run_script("$scriptsdir/$package.postrm", 'post-removal script for purge',
+                    'purge');
+        unlink("$scriptsdir/$package.postrm") || $! == &ENOENT ||
+            &error("$arg: cannot remove old postrm script: $!");
+        &setnotinstalled;
+        @undo= ();
+    } elsif (!@configf && !stat("$scripts/$package.postrm")) {
+        # If there are no config files and no postrm script then we
+        # go straight into `purge'.  However, perhaps the stat didn't
+        # fail with ENOENT ...
+        $! == &ENOENT || &error("$package: stat failed on postrm script: $!");
+        $st_p2w{$package}= 'purge';
+        &setnotinstalled;
+    }
+    $st_p2h{$package}= 'ok'; $statusupdated{$package}= 1;
+}
+
+sub setnotinstalled {             
+    unlink("$listsdir/$package.list") ||
+        &error("$arg: unable to delete old file list: $!");
+    $st_p2s{$package}= 'not-installed';
+    for $k (keys %all_k21) { delete $st_pk2v{$package,$k}; }
+}
+
+#*** dependency processing - common to --configure and --remove ***#
+
+# The algorithm for deciding what to configure or remove first is as
+# follows:
+#
+# Loop through all packages doing a `try 1' until we've been round and
+# nothing has been done, then do `try 2' and `try 3' likewise.
+#
+# When configuring, in each try we check to see whether all
+# dependencies of this package are done.  If so we do it.  If some of
+# the dependencies aren't done yet but will be later we defer the
+# package, otherwise it is an error.
+#
+# When removing, in each try we check to see whether there are any
+# packages that would have dependencies missing if we removed this
+# one.  If not we remove it now.  If some of these packages are
+# themselves scheduled for removal we defer the package until they
+# have been done.
+#
+# The criteria for satisfying a dependency vary with the various
+# tries.  In try 1 we treat the dependencies as absolute.  In try 2 we
+# check break any cycles in the dependency graph involving the package
+# we are trying to process before trying to process the package
+# normally.  In try 3 (which should only be reached if
+# --force-depends-version is set) we ignore version number clauses in
+# Depends lines.  In try 4 (only reached if --force-depends is set) we
+# say "ok" regardless.
+#
+# If we are configuring and one of the packages we depend on is
+# awaiting configuration but wasn't specified in the argument list we
+# will add it to the argument list if --configure-any is specified.
+# In this case we note this as having "done something" so that we
+# don't needlessly escalate to higher levels of dependency checking
+# and breaking.
+
+sub dependencies_ok {
+    local ($dp, $removingp) = @_;
+    local ($tpo, $however_t, $ok, $found, @aemsgs, @oemsgs);
+    local ($tp, $rightver, $inst, $want, $thisf, $matched, $tpp);
+    $ok= 2; # 2=ok, 1=defer, 0=halt
+    &debug("checking dependencies of $dp (- $removingp)");
+    for $tpo (split(/,/, $st_pk2v{$dp,'depends'})) {
+       $tpo =~ s/^\s*//; $tpo =~ s/\s+$//;
+       &debug("  checking group $dp -> $tpo");
+        $matched= 0; @oemsgs=();
+        $found=0; # 0=none, 1=defer, 2=withwarning, 3=ok
+        for $tp (split(/\|/, $tpo)) {
+           $tp =~ s/^\s*//; $tp =~ s/\s+$//;
+           &debug("  checking possibility $dp -> $tp");
+            if ($ignore_depends{$tp}) { &debug("ignoring so ok"); $found=3; last; }
+            if (defined($cyclebreak{$dp,$tp})) { &debug("break cycle"); $found=3; last; }
+            if ($tp eq $removingp) {
+                ($tps, $rightver, $inst, $want, $tpp)= ('removing-now', 1, '','', $tp);
+                $matched= 1;
+            } else {
+                ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
+                &debug("installationstatus($tp) -> !$tps!$rightver!$inst!$want!$tps|");
+            }
+            if (($tps eq 'installed' || $tps eq 'unpacked' || $tps eq 'postinst-failed')
+                && !$rightver) {
+                push(@oemsgs,"version of $tpp on system is $inst (wanted $want)");
+                if ($force{'depends'}) { $thisf= $dependtry >= 3 ? 2 : 1; }
+            } elsif ($tps eq 'unpacked' || $tps eq 'postinst-failed') {
+                if (grep($_ eq $tpp, @deferred)) {
+                    $thisf=1;
+                } elsif (!length($removingp) && $force{'configure-any'}) {
+                    &warn("will also configure $tpp");
+                    push(@deferred,$tpp); $sincenothing=0; $thisf=1;
+                } else {
+                    push(@oemsgs,"package $tpp is not configured yet");
+                    if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
+                }
+            } elsif ($tps eq 'installed') {
+                $found=3; last;
+            } elsif ($tps eq 'removing-now') {
+                push(@oemsgs,"$tpp is to be removed");
+                if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
+            } else {
+                push(@oemsgs,"$tpp ($want) is not installed");
+                if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
+            }
+           &debug(" found $found");
+            $found=$thisf if $thisf>$found;
+        }
+       &debug(" found $found matched $matched");
+        next if length($removingp) && !$matched;
+        if (length($removingp) && $tpo !~ m/\|/) {
+            $however_t= '';
+        } elsif (@oemsgs > 1) {
+            $however_t= "\n  However, ". join(",\n   ", @oemsgs[0..($#oemsgs-1)]).
+                      " and\n   ". $oemsgs[$#oemsgs]. ".";
+        } else {
+            $however_t= "\n  However, @oemsgs.";
+        }
+        if ($found == 0) {
+            push(@aemsgs, "$dp depends on $tpo.$however_t");
+            $ok=0;
+        } elsif ($found == 1) {
+            $ok=1 if $ok>1;
+        } elsif ($found == 2) {
+            push(@aemsgs, "$dp depends on $tpo.$however_t");
+        } elsif ($found != 3) {
+            &internalerr("found value in deferred_configure $found not known");
+        }
+    }
+    &debug("ok $ok msgs >>@aemsgs<<");
+    return ($ok, @aemsgs);
+}
+
+sub findbreakcycle {
+    # Cycle breaking works recursively down the package dependency
+    # tree.  @sofar is the list of packages we've descended down
+    # already - if we encounter any of its packages again in a
+    # dependency we have found a cycle.
+    #
+    # Cycles are preferentially broken by ignoring a dependency from
+    # a package which doesn't have a postinst script.  If there isn't
+    # such a dependency in the cycle we break at the `start' of the
+    # cycle from the point of view of our package.
+    #
+    local ($package,@sofar) = @_;
+    local ($tp,$tpp,$tps,$rightver,$inst,$want,$i,$dr,$de,@sf);
+    &debug("findbreakcycle($package; @sofar)");
+    push(@sofar,$package);
+    for $tp (split(/[,|]/, $st_pk2v{$package,'depends'})) {
+       $tp =~ s/^\s*//; $tp =~ s/\s+$//;
+        ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
+        next unless $tps eq 'config-files' || $tps eq 'unpacked';
+        next if $cyclebreak{$package,$tpp};
+        if (grep($_ eq $tpp, @sofar)) {
+            &debug("found cycle $package, $tpp (@sofar)");
+            @sf= (@sofar,$tpp);
+            for ($i=0;
+                 $i<$#sf;
+                 $i++) {
+                next if stat("$scriptsdir/$sf[$i].postinst");
+                last if $! == &ENOENT;
+                &error("$arg: unable to stat $scriptsdir/$sf[$i].postinst: $!");
+            }
+            $i=0 if $i>=$#sf;
+            ($dr,$de)= @sf[$i..$i+1];
+           if (!defined($cyclebreak{$dr,$de})) {
+               $sincenothing=0; $cyclebreak{$dr,$de}= 1;
+               &debug("broken cycle $i (@sf) at $dr -> $de");
+                return 1;
+           }
+        } else {
+            return if &findbreakcycle($tpp,@sofar);
+        }
+    }
+    return 0;
+}
+
+#*** useful subroutines for actions ***#
+
+sub filesinpackage {
+    # Returns the list in @ilist.
+    # If error, calls &error("$epfx: ...");
+    local ($epfx, $package) = @_;
+    open(LIST,"$listsdir/$package.list") ||
+        &error("$epfx: database broken for $package - ".
+               "can't get installed files list: $!");
+    @ilist= <LIST>;
+    eof || &error("$epfx: cannot read $listsdir/$package.list: $!");
+    close(LIST);
+    @ilist= grep((chop,
+                  s|/$||,
+                  m|^/| || s|^|/|,
+                  m/./),
+                 @ilist);
+}
+
+sub installationstatus {
+    local ($controlstring) = @_;
+    local ($lversion,$lpackage,$lstatus,$lrevision,$cmp) = @_;
+    local ($cc);
+    $lversion= $controlstring;
+    $lversion =~ s/^($packagere)\s*// ||
+        &internalerr("needed installation status of bogus thing \`$lversion'");
+    $lpackage= $1;
+    $lstatus= defined($st_p2s{$lpackage}) ? $st_p2s{$lpackage} : 'not-installed';
+    if ($lstatus ne 'not-installed') {
+       if (length($lversion)) {
+           $lversion =~ s/^\s*\(\s*// && $lversion =~ s/\s*\)\s*$// ||
+               &internalerr("failed to strip version \`$lversion'");
+            if ($lversion =~ s/^[><=]//) { $cc= $&; } else { $cc= '='; }
+           $lrevision = ($lversion =~ s/-([^-]+)$//) ? $1 : '';
+           $wantedstring= "version $lversion";
+            $wantedstring .= ", package revision $lrevision" if length($lrevision);
+            $cmp= &compare_verrevs($st_pk2v{$lpackage,'version'},
+                                   $st_pk2v{$lpackage,'package_revision'},
+                                   $lversion,
+                                   $lrevision);
+            $installedstring= "version $st_pk2v{$lpackage,'version'}";
+            $installedstring .=
+                ", package revision $st_pk2v{$lpackage,'package_revision'}"
+                    if length($st_pk2v{$lpackage,'package_revision'});
+            if ($cc eq '>') {
+                $rightver= $cmp>=0; $wantedstring.= ' or later';
+            } elsif ($cc eq '<') {
+                $rightver= $cmp<=0; $wantedstring.= ' or earlier';
+            } else {
+                s/^=//;
+                $rightver= !$cmp; $wantedstring= "exactly $wantedstring";
+            }
+       } else {
+           $rightver= 1;
+           $wantedstring= "any version";
+           $installedstring= $st_pk2v{$lpackage,'version'}.'-'.
+                              $st_pk2v{$lpackage,'package_revision'};
+       }
+    } else {
+       $rightver= -1;
+       $installedstring= "not installed";
+    }
+    return ($lstatus,$rightver,$installedstring,$wantedstring,$lpackage);
+}
+
+sub parse_control {
+    # reads from fh CONTROL
+    local ($fn) = @_;
+    local ($cf,$ln,$l,$k,$v);
+    defined($cf= &readall('CONTROL')) || &error("read control file $fn: $!");
+    close(CONTROL);
+    $p= &parse_control_entry;
+    if (@cwarnings) {
+        &warn("$fn: control file contains oddities: ".join("; ",@cwarnings))
+            unless $controlwarn;
+    }
+    if (@cerrors) {
+        &error("$fn: control file contains errors: ".join("; ",@cerrors));
+    }
+}
+
+sub run_script_ne {
+    local ($script,$describe,@args) = @_;
+    local ($extranewlines) = $script =~ m/postinst/;
+    &debug("running $describe = $script @args");
+    if (!stat("$script")) {
+        return if $! == &ENOENT;
+        die "couldn't stat $script: $!\n";
+    }
+    if (! -x _) {
+        chmod(0755, "$script") || die "couldn't make $script executable: $!\n";
+    }
+    print "\n" if $extranewlines;
+    &debug("forking now");
+    defined($rsc= fork) || die "couldn't fork for running $script: $!\n";
+    if (!$rsc) {
+        if ($instroot !~ m|^/*$| && !chroot($instroot)) {
+            print STDERR "$name: failed to chroot to $instroot for $describe: $!\n";
+            exit(1);
+        }
+        exec($script,@args);
+        print STDERR "$name: failed to exec $script: $!\n";
+        exit(1);
+    }
+    $!=0; waitpid($rsc,0) == $rsc || die "couldn't wait for $describe: $!\n";
+    $? && die "$describe failed (".&ecode.")\n";
+    &debug("script done");
+    print "\n" if $extranewlines;
+}
+
+sub run_script {
+    return if eval { &run_script_ne; 1; };
+    $rse= $@; chop($rse); &error("$package: $rse");
+}
+
+sub hash {
+    local ($file) = @_; # NB: filename must already have $instroot here
+    local ($c);
+    if (open(HF,"<$file")) {
+        defined($c= open(MDP,"-|")) || &error("fork/pipe for hash: $!");
+        if (!$c) {
+            if (!open(STDIN,"<&HF")) {
+                print STDERR "$name: unable to redirect stdin for hash: $!\n"; exit(1);
+            }
+            exec($md5sum); print STDERR "$name: unable to exec $md5sum: $!\n"; exit(1);
+        }
+        defined($hash= &readall('MDP')) || &error("unable to read from $md5sum: $!\n");
+        $!=0; close(MDP); $? && &error("$md5sum returned error (".&ecode.")");
+        $hash =~ s/\n+$//;
+        $hash =~ m/^[0-9a-f]{32}$/i || &error("$md5sum returned bogus output \`$hash'");
+        return $hash;
+    } elsif ($! == &ENOENT) {
+        return 'nonexistent';
+    } else {
+        &warn("$arg: unable to open conffile $file for hash: $!");
+        return '-';
+    }
+}
+
+sub files_not_identical {
+    local ($file1,$file2) = @_; # NB: filenames must already have $instroot here
+    if (stat($file1)) {
+        if (stat($file2)) {
+            system("cmp","-s",$file1,$file2);
+            if (&WIFEXITED($?)) {
+                $es= &WEXITSTATUS($?);
+                return $es if $es == 0 || $es == 1;
+            }
+            &error("cmp $file1 $file2 returned error (".&ecode.")");
+        } elsif ($! == &ENOENT) {
+            return 1;
+        } else {
+            &error("failed to stat conffile $file2: $!");
+        }
+    } elsif ($! == &ENOENT) {
+        if (stat($file2)) {
+            return 1;
+        } elsif ($! == &ENOENT) {
+            return 0;
+        } else {
+            &error("failed to stat conffile $file2: $!");
+        }
+    } else {
+        &error("failed to stat conffile $file1: $!");
+    }
+}
+
+sub copyperm {
+    local ($from,$to,$name) = @_;
+    if (@statv= stat("$instroot/$from")) {
+        chown($statv[4],$statv[5],"$instroot/$to") ||
+            $!==&ENOENT ||
+                &warn("$package: unable to preserve ownership of $name");
+        chmod($statv[2],"$instroot/$to") ||
+            $!==&ENOENT ||
+                &warn("$package: unable to preserve permissions of $name");
+    } elsif ($! != &ENOENT) {
+        &warn("$package: unable to check permissions and ownership of".
+              " $name in order to preserve them");
+    }
+}
+
+sub conffderef {
+    local ($file) = @_;
+    local ($drf, $warning);
+    $drf= $file; $warning='';
+    for (;;) {
+        if (!lstat("$instroot/$drf")) {
+            last if $! == &ENOENT; $warning= "unable to lstat: $!"; last;
+        } elsif (-f _) {
+            last;
+        } elsif (-l _) {
+            if (!defined($lv= readlink("$instroot/$drf"))) {
+                $warning= "unable to readlink: $!"; last;
+            }
+            if ($lv =~ m|^/|) {
+                $drf= $lv;
+            } else {
+                $drf =~ s|/[^/]+$|/$lv|;
+            }
+        } else {
+            $warning= "not a plain file or symlink"; last;
+        }
+    }
+    &debug("conffile $file drf $drf warns \`$warning'");
+    if ($warning) {
+        &warn("$arg: possible problem with configuration file $file (= $drf):\n".
+              " $warning");
+        return undef;
+    } else {
+        return $drf;
+    }
+}
diff --git a/scripts/start-stop-daemon.8 b/scripts/start-stop-daemon.8
new file mode 100644 (file)
index 0000000..7870720
--- /dev/null
@@ -0,0 +1,19 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH START\-STOP\-DAEMON 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+start\-stop\-daemon \- Debian package installation tool
+.SH DESCRIPTION
+.B start\-stop\-daemon
+does not have a useful man page.  Please do not report this as a bug,
+as this has already been done many times.
+
+Instead, if you are a competent and accurate writer and are willing to
+spend the time reading the source code and writing good manpages
+please write a better man page than this one.
+
+Type
+.B start\-stop\-daemon \-\-help
+for a brief summary of how to use dpkg.
+
+.SH AUTHOR
+Ian Jackson <ijackson@gnu.ai.mit.edu>.
diff --git a/scripts/start-stop-daemon.pl b/scripts/start-stop-daemon.pl
new file mode 100755 (executable)
index 0000000..ecfeb89
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/perl --
+
+$version= '0.93.30'; # This line modified by Makefile
+sub usageversion {
+    print(STDERR <<END)
+Debian GNU/Linux start-stop-daemon $version.  Copyright (C) 1995
+Ian Jackson.  This is free software; see the GNU General Public Licence
+version 2 or later for copying conditions.  There is NO warranty.
+
+Usage: start-stop-daemon --start | --stop | --version|--help  options ...
+Options:  --test  --oknodo    --exec <executable>  --pidfile <pid-file>
+          --quiet|--verbose   --user <username>|<uid>  --name <process-name>
+          --signal <signal>  --startas <pathname>
+          -- <... all of the rest are arguments to daemon ...>
+ Be careful - try not to call without --exec.  \`start-stop-daemon --stop'
+ would send a SIGTERM to every process, if it weren't specially prevented.
+
+Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = trouble
+END
+        || &quit("failed to write usage: $!");
+}
+sub quit { print STDERR "start-stop-daemon: @_\n"; exit(2); }
+sub badusage { print STDERR "start-stop-daemon: @_\n\n"; &usageversion; exit(2); }
+
+$exitnodo= 1;
+$quietmode= 0;
+$signal= 15;
+undef $operation;
+undef $exec;
+undef $pidfile;
+undef $user;
+undef $name;
+undef $startas;
+
+while (@ARGV) {
+    $_= shift(@ARGV);
+    last if m/^--$/;
+    if (!m/^--/) {
+        &quit("unknown argument \`$_'");
+    } elsif (m/^--(help|version)$/) {
+        &usageversion; exit(0);
+    } elsif (m/^--test$/) {
+        $testmode= 1;
+    } elsif (m/^--quiet$/) {
+        $quietmode= 1;
+    } elsif (m/^--verbose$/) {
+        $quietmode= -1;
+    } elsif (m/^--oknodo$/) {
+        $exitnodo= 0;
+    } elsif (m/^--(start|stop)$/) {
+        $operation= $1; next;
+    } elsif (m/^--signal$/) {
+        $_= shift(@ARGV); m/^\d+$/ || &badusage("--signal takes a numeric argument");
+        $signal= $_;
+    } elsif (m/^--(exec|pidfile|name|startas)$/) {
+        defined($_= shift(@ARGV)) || &badusage("--$1 takes an argument");
+        eval("\$$1= \$_");
+    } elsif (m/^--user$/) {
+        defined($_= shift(@ARGV)) || &badusage("--user takes a username argument");
+        if (m/^\d+$/) {
+            $user= $_;
+        } else {
+            (@u= getpwnam($_)) || &quit("user \`$_' not found");
+            $user= $u[2];
+        }
+        $userspec= $_;
+    } else {
+        &badusage("unknown option \`$_'");
+    }
+}
+
+defined($operation) ||
+    &badusage("need --start or --stop");
+defined($exec) || defined($pidfile) || defined($user) ||
+    &badusage("need at least one of --exec, --pidfile or --user");
+$startas= $exec if !defined($startas);
+$operation ne 'start' || defined($startas) ||
+    &badusage("--start needs --exec or --startas");
+
+if (defined($exec)) {
+    $exec =~ s,^,./, unless $exec =~ m,^[./],;
+    (@ve= stat("$exec")) || &quit("unable to stat executable \`$exec': $!");
+}
+
+@found= ();
+if (defined($pidfile)) {
+    $pidfile =~ s,^,./, unless $pidfile =~ m,^[./],;
+    if (open(PID,"< $pidfile")) {
+        $pid= <PID>;
+        &check($1) if $pid =~ m/^\s*(\d+)\s*$/;
+        close(PID);
+    }
+} else {
+    opendir(PROC,"/proc") || &quit("failed to opendir /proc: $!");
+    $foundany= 0;
+    while (defined($pid= readdir(PROC))) {
+        next unless $pid =~ m/^\d+$/;
+        $foundany++; &check($pid);
+    }
+    $foundany || &quit("nothing in /proc - not mounted ?");
+}
+
+sub check {
+    local ($p)= @_;
+    if (defined($exec)) {
+        return unless @vp= stat("/proc/$p/exe");
+        return unless $vp[0] eq $ve[0] && $vp[1] eq $ve[1];
+    } 
+    open(C,"/proc/$p/stat");
+    (@vs= stat(C)) || return;
+    if (defined($user)) {
+        (close(C), return) unless $vs[4] == $user;
+    }
+    if (defined($name)) {
+        $c= <C>; close(C);
+        return unless $c =~ m/^$p \(([^\)]*)\) / && $1 eq $name;
+    }
+    close(C);
+    push(@found,$p);
+}
+
+if ($operation eq 'start') {
+    if (@found) {
+        print "$exec already running.\n" unless $quietmode>0;
+        exit($exitnodo);
+    }
+    if ($testmode) {
+        print "would start $startas @ARGV.\n";
+        exit(0);
+    }
+    print "starting $exec ...\n" if $quietmode<0;
+    exec($startas,@ARGV);
+    &quit("unable to start $exec: $!");
+}
+
+$what= defined($name) ? $name :
+       defined($exec) ? $exec :
+       defined($pidfile) ? "process in pidfile \`$pidfile'" :
+       defined($user) ? "process(es) owned by \`$userspec'" :
+           &quit("internal error, this is a bug - please report:".
+                 " no name,exec,pidfile,user");
+
+if (!@found) {
+    print "no $what found; none killed.\n" unless $quietmode>0;
+    exit($exitnodo);
+}
+
+for $pid (@found) {
+    if ($testmode) {
+        print "would send signal $signal to $pid.\n";
+    } else {
+        if (kill($signal,$pid)) {
+            push(@killed,$pid);
+        } else {
+            print "start-stop-daemon: warning: failed to kill $pid: $!\n"; #
+        }
+    }
+}
+print "stopped $what (pid @killed).\n" if $quietmode<0;
+exit(0);
diff --git a/scripts/update-alternatives.8 b/scripts/update-alternatives.8
new file mode 100644 (file)
index 0000000..d6719af
--- /dev/null
@@ -0,0 +1,19 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH UPDATE\-ALTERNATIVES 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+update\-alternatives \- Debian package installation tool
+.SH DESCRIPTION
+.B update\-alternatives
+does not have a useful man page.  Please do not report this as a bug,
+as this has already been done many times.
+
+Instead, if you are a competent and accurate writer and are willing to
+spend the time reading the source code and writing good manpages
+please write a better man page than this one.
+
+Type
+.B update\-alternatives \-\-help
+for a brief summary of how to use dpkg.
+
+.SH AUTHOR
+Ian Jackson <ijackson@gnu.ai.mit.edu>.
diff --git a/scripts/update-alternatives.pl b/scripts/update-alternatives.pl
new file mode 100755 (executable)
index 0000000..a961253
--- /dev/null
@@ -0,0 +1,429 @@
+#!/usr/bin/perl --
+
+#use POSIX; &ENOENT;
+sub ENOENT { 2; }
+# Sorry about this, but POSIX.pm isn't necessarily available
+
+$version= '0.93.80'; # This line modified by Makefile
+sub usageversion {
+    print(STDERR <<END)
+Debian GNU/Linux update-alternatives $version.  Copyright (C) 1995
+Ian Jackson.  This is free software; see the GNU General Public Licence
+version 2 or later for copying conditions.  There is NO warranty.
+
+Usage: update-alternatives --install <link> <name> <path> <priority>
+                          [--slave <link> <name> <path>] ...
+       update-alternatives --remove <name> <path>
+       update-alternatives --auto <name>
+       update-alternatives --display <name>
+<name> is the name in /etc/alternatives.
+<path> is the name referred to.
+<link> is the link pointing to /etc/alternatives/<name>.
+<priority> is an integer; options with higher numbers are chosen.
+
+Options:  --verbose|--quiet  --test  --help  --version
+          --altdir <directory>  --admindir <directory>
+END
+        || &quit("failed to write usage: $!");
+}
+sub quit { print STDERR "update-alternatives: @_\n"; exit(2); }
+sub badusage { print STDERR "update-alternatives: @_\n\n"; &usageversion; exit(2); }
+
+$altdir= '/etc/alternatives';
+$admindir= '/var/lib/dpkg/alternatives';
+$testmode= 0;
+$verbosemode= 0;
+$mode='';
+$manual= 'auto';
+$|=1;
+
+sub checkmanymodes {
+    return unless $mode;
+    &badusage("two modes specified: $_ and --$mode");
+}
+
+while (@ARGV) {
+    $_= shift(@ARGV);
+    last if m/^--$/;
+    if (!m/^--/) {
+        &quit("unknown argument \`$_'");
+    } elsif (m/^--(help|version)$/) {
+        &usageversion; exit(0);
+    } elsif (m/^--test$/) {
+        $testmode= 1;
+    } elsif (m/^--verbose$/) {
+        $verbosemode= +1;
+    } elsif (m/^--quiet$/) {
+        $verbosemode= -1;
+    } elsif (m/^--install$/) {
+        &checkmanymodes;
+        @ARGV >= 4 || &badusage("--install needs <link> <name> <path> <priority>");
+        ($alink,$name,$apath,$apriority,@ARGV) = @ARGV;
+        $apriority =~ m/^[-+]?\d+/ || &badusage("priority must be an integer");
+        $mode= 'install';
+    } elsif (m/^--remove$/) {
+        &checkmanymodes;
+        @ARGV >= 2 || &badusage("--remove needs <name> <path>");
+        ($name,$apath,@ARGV) = @ARGV;
+        $mode= 'remove';
+    } elsif (m/^--(display|auto)$/) {
+        &checkmanymodes;
+        @ARGV || &badusage("--$1 needs <name>");
+        $mode= $1;
+        $name= shift(@ARGV);
+    } elsif (m/^--slave$/) {
+        @ARGV >= 3 || &badusage("--slave needs <link> <name> <path>");
+        ($slink,$sname,$spath,@ARGV) = @ARGV;
+        defined($aslavelink{$sname}) && &badusage("slave name $sname duplicated");
+        $aslavelinkcount{$slink}++ && &badusage("slave link $slink duplicated");
+        $aslavelink{$sname}= $slink;
+        $aslavepath{$sname}= $spath;
+    } elsif (m/^--altdir$/) {
+        @ARGV && &badusage("--altdir needs a <directory> argument");
+        $altdir= shift(@ARGV);
+    } elsif (m/^--admindir$/) {
+        @ARGV && &badusage("--admindir needs a <directory> argument");
+        $admindir= shift(@ARGV);
+    } else {
+        &badusage("unknown option \`$_'");
+    }
+}
+
+defined($aslavelink{$name}) && &badusage("name $name is both primary and slave");
+$aslavelinkcount{$alink} && &badusage("link $link is both primary and slave");
+
+$mode || &badusage("need --display, --install, --remove or --auto");
+$mode eq 'install' || !%slavelink || &badusage("--slave only allowed with --install");
+
+if (open(AF,"$admindir/$name")) {
+    $manual= &gl("manflag");
+    $manual eq 'auto' || $manual eq 'manual' || &badfmt("manflag");
+    $link= &gl("link");
+    while (($sname= &gl("sname")) ne '') {
+        push(@slavenames,$sname);
+        defined($slavenum{$sname}) && &badfmt("duplicate slave $tsname");
+        $slavenum{$sname}= $#slavenames;
+        $slink= &gl("slink");
+        $slink eq $link && &badfmt("slave link same as main link $link");
+        $slavelinkcount{$slink}++ && &badfmt("duplicate slave link $slink");
+        push(@slavelinks,$slink);
+    }
+    while (($version= &gl("version")) ne '') {
+        defined($versionnum{$version}) && &badfmt("duplicate path $tver");
+        push(@versions,$version);
+        $versionnum{$version}= $i= $#versions;
+        $priority= &gl("priority");
+        $priority =~ m/^[-+]?\d+$/ || &badfmt("priority $version $priority");
+        $priorities[$i]= $priority;
+        for ($j=0; $j<=$#slavenames; $j++) {
+            $slavepath{$i,$j}= &gl("spath");
+        }
+    }
+    close(AF);
+    $dataread=1;
+} elsif ($! != &ENOENT) {
+    &quit("failed to open $admindir/$name: $!");
+}
+
+if ($mode eq 'display') {
+    if (!$dataread) {
+        &pr("No alternatives for $name.");
+    } else {
+        &pr("$name - status is $manual.");
+        if (defined($linkname= readlink("$altdir/$name"))) {
+            &pr(" link currently points to $linkname");
+        } elsif ($! == &ENOENT) {
+            &pr(" link currently absent");
+        } else {
+            &pr(" link unreadable - $!");
+        }
+        $best= '';
+        for ($i=0; $i<=$#versions; $i++) {
+            if ($best eq '' || $priorities[$i] > $bestpri) {
+                $best= $versions[$i]; $bestpri= $priorities[$i];
+            }
+            &pr("$versions[$i] - priority $priorities[$i]");
+            for ($j=0; $j<=$#slavenames; $j++) {
+                next unless length($tspath= $slavepath{$i,$j});
+                &pr(" slave $slavenames[$j]: $tspath");
+            }
+        }
+        if ($best eq '') {
+            &pr("No versions available.");
+        } else {
+            &pr("Current \`best' version is $best.");
+        }
+    }
+    exit 0;
+}
+
+$best= '';
+for ($i=0; $i<=$#versions; $i++) {
+    if ($best eq '' || $priorities[$i] > $bestpri) {
+        $best= $versions[$i]; $bestpri= $priorities[$i];
+    }
+}
+
+if (defined($linkname= readlink("$altdir/$name"))) {
+    if ($linkname eq $best) {
+        $state= 'expected';
+    } elsif (defined($linkname2= readlink("$altdir/$name.dpkg-tmp"))) {
+        $state= 'expected-inprogress';
+    } else {
+        $state= 'unexpected';
+    }
+} elsif ($! == &ENOENT) {
+    $state= 'nonexistent';
+} else {
+    $state= 'unexpected';
+}
+
+# Possible values for:
+#   $manual      manual, auto
+#   $state       expected, expected-inprogress, unexpected, nonexistent
+#   $mode        auto, install, remove
+# all independent
+
+if ($mode eq 'auto') {
+    &pr("Setting up automatic selection of $name.");
+    unlink("$altdir/$name.dpkg-tmp") || $! == &ENOENT ||
+        &quit("unable to remove $altdir/$name.dpkg-tmp: $!");
+    unlink("$altdir/$name") || $! == &ENOENT ||
+        &quit("unable to remove $altdir/$name.dpkg-tmp: $!");
+    $state= 'nonexistent';
+    $manual= 'auto';
+} elsif ($state eq 'nonexistent') {
+    if ($mode eq 'manual') {
+        &pr("$altdir/$name has been deleted, returning to automatic selection.");
+        $mode= 'auto';
+    }
+}
+
+#   $manual      manual, auto
+#   $state       expected, expected-inprogress, unexpected, nonexistent
+#   $mode        auto, install, remove
+# mode=auto <=> state=nonexistent
+
+if ($state eq 'unexpected' && $manual eq 'auto') {
+    &pr("$altdir/$name has been changed (manually or by a script).\n".
+        "Switching to manual updates only.");
+    $manual= 'manual';
+}
+
+#   $manual      manual, auto
+#   $state       expected, expected-inprogress, unexpected, nonexistent
+#   $mode        auto, install, remove
+# mode=auto <=> state=nonexistent
+# state=unexpected => manual=manual
+
+&pr("Checking available versions of $name, updating links in $altdir ...\n".
+    "(You may modify the symlinks there yourself if desired - see \`man ln'.)");
+
+if ($mode eq 'install') {
+    if ($link ne $alink && $link ne '') {
+        &pr("Renaming $name link from $link to $alink.");
+        rename($link,$alink) || $! == &ENOENT ||
+            &quit("unable to rename $link to $alink: $!");
+    }
+    $link= $alink;
+    if (!defined($i= $versionnum{$apath})) {
+        push(@versions,$apath);
+        $versionnum{$apath}= $i= $#versions;
+    }
+    $priorities[$i]= $apriority;
+    for $sname (keys %aslavelink) {
+        if (!defined($j= $slavenum{$sname})) {
+            push(@slavenames,$sname);
+            $slavenum{$sname}= $j= $#slavenames;
+        }
+        $oldslavelink= $slavelinks[$j];
+        $newslavelink= $aslavelink{$sname};
+        $slavelinkcount{$oldslavelink}-- if $oldslavelink ne '';
+        $slavelinkcount{$newslavelink}++ &&
+            &quit("slave link name $newslavelink duplicated");
+        if ($newslavelink ne $oldslavelink && $oldslavelink ne '') {
+            &pr("Renaming $sname slave link from $oldslavelink to $newslavelink.");
+            rename($oldslavelink,$newslavelink) || $! == &ENOENT ||
+                &quit("unable to rename $oldslavelink to $newslavelink: $!");
+        }
+        $slavelinks[$j]= $newslavelink;
+    }
+    for ($j=0; $j<=$#slavenames; $j++) {
+        $slavepath{$i,$j}= $aslavepath{$slavenames[$j]};
+    }
+}
+
+if ($mode eq 'remove') {
+    if (defined($i= $versionnum{$apath})) {
+        $k= $#versions;
+        $versionnum{$versions[$k]}= $i;
+        delete $versionnum{$versions[$i]};
+        $versions[$i]= $versions[$k]; $#versions--;
+        $priorities[$i]= $priorities[$k]; $#priorities--;
+        for ($j=0; $j<=$#slavenames; $j++) {
+            $slavepath{$i,$j}= $slavepath{$k,$j};
+            delete $slavepath{$k,$j};
+        }
+    } else {
+        &pr("Alternative $apath for $name not registered, not removing.");
+    }
+}
+
+for ($j=0; $j<=$#slavenames; $j++) {
+    for ($i=0; $i<=$#versions; $i++) {
+        last if $slavepath{$i,$j} ne '';
+    }
+    if ($i > $#versions) {
+        &pr("Discarding obsolete slave link $slavenames[$j] ($slavelinks[$j]).");
+        unlink("$altdir/$slavenames[$j]") || $! == &ENOENT ||
+            &quit("unable to remove $slavenames[$j]: $!");
+        unlink($slavelinks[$j]) || $! == &ENOENT ||
+            &quit("unable to remove $slavelinks[$j]: $!");
+        $k= $#slavenames;
+        $slavenum{$slavenames[$k]}= $j;
+        delete $slavenum{$slavenames[$j]};
+        $slavelinkcount{$slavelinks[$j]}--;
+        $slavenames[$j]= $slavenames[$k]; $#slavenames--;
+        $slavelinks[$j]= $slavelinks[$k]; $#slavelinks--;
+        for ($i=0; $i<=$#versions; $i++) {
+            $slavepath{$i,$j}= $slavepath{$i,$k};
+            delete $slavepath{$i,$k};
+        }
+        $j--;
+    }
+}
+        
+if ($manual eq 'manual') {
+    &pr("Automatic updates of $altdir/$name are disabled, leaving it alone.");
+    &pr("To return to automatic updates use \`update-alternatives --auto $name'.");
+} else {
+    if ($state eq 'expected-inprogress') {
+        &pr("Recovering from previous failed update of $name ...");
+        rename("$altdir/$name.dpkg-tmp","$altdir/$name") ||
+            &quit("unable to rename $altdir/$name.dpkg-tmp to $altdir/$name: $!");
+        $state= 'expected';
+    }
+}
+
+#   $manual      manual, auto
+#   $state       expected, expected-inprogress, unexpected, nonexistent
+#   $mode        auto, install, remove
+# mode=auto <=> state=nonexistent
+# state=unexpected => manual=manual
+# manual=auto => state!=expected-inprogress && state!=unexpected
+
+open(AF,">$admindir/$name.dpkg-new") ||
+    &quit("unable to open $admindir/$name.dpkg-new for write: $!");
+&paf($manual);
+&paf($link);
+for ($j=0; $j<=$#slavenames; $j++) {
+    &paf($slavenames[$j]);
+    &paf($slavelinks[$j]);
+}
+&paf('');
+$best= '';
+for ($i=0; $i<=$#versions; $i++) {
+    if ($best eq '' || $priorities[$i] > $bestpri) {
+        $best= $versions[$i]; $bestpri= $priorities[$i]; $bestnum= $i;
+    }
+    &paf($versions[$i]);
+    &paf($priorities[$i]);
+    for ($j=0; $j<=$#slavenames; $j++) {
+        &paf($slavepath{$i,$j});
+    }
+}
+&paf('');
+close(AF) || &quit("unable to close $admindir/$name.dpkg-new: $!");
+
+if ($manual eq 'auto') {
+    if ($best eq '') {
+        &pr("Last package providing $name ($link) removed, deleting it.");
+        unlink("$altdir/$name") || $! == &ENOENT ||
+            &quit("unable to remove $altdir/$name: $!");
+        unlink("$link") || $! == &ENOENT ||
+            &quit("unable to remove $altdir/$name: $!");
+        unlink("$admindir/$name.dpkg-new") ||
+            &quit("unable to remove $admindir/$name.dpkg-new: $!");
+        unlink("$admindir/$name") || $! == &ENOENT ||
+            &quit("unable to remove $admindir/$name: $!");
+        exit(0);
+    } else {
+        if (!defined($linkname= readlink($link)) && $! != &ENOENT) {
+            &pr("warning: $link is supposed to be a symlink to $altdir/$name\n".
+                " (or nonexistent); however, readlink failed: $!");
+        } elsif ($linkname ne "$altdir/$name") {
+            unlink("$link.dpkg-tmp") || $! == &ENOENT ||
+                &quit("unable to ensure $link.dpkg-tmp nonexistent: $!");
+            symlink("$altdir/$name","$link.dpkg-tmp") ||
+                &quit("unable to make $link.dpkg-tmp a symlink to $altdir/$name: $!");
+            rename("$link.dpkg-tmp",$link) ||
+                &quit("unable to install $link.dpkg-tmp as $link: $!");
+        }
+        if (defined($linkname= readlink("$altdir/$name")) && $linkname eq $best) {
+            &pr("Leaving $name ($link) pointing to $best.");
+        } else {
+            &pr("Updating $name ($link) to point to $best.");
+        }
+        unlink("$altdir/$name.dpkg-tmp") || $! == &ENOENT ||
+            &quit("unable to ensure $altdir/$name.dpkg-tmp nonexistent: $!");
+        symlink($best,"$altdir/$name.dpkg-tmp");
+    }
+}
+
+rename("$admindir/$name.dpkg-new","$admindir/$name") ||
+    &quit("unable to rename $admindir/$name.dpkg-new to $admindir/$name: $!");
+
+if ($manual eq 'auto') {
+    rename("$altdir/$name.dpkg-tmp","$altdir/$name") ||
+        &quit("unable to install $altdir/$name.dpkg-tmp as $altdir/$name");
+    for ($j=0; $j<=$#slavenames; $j++) {
+        $sname= $slavenames[$j];
+        $slink= $slavelinks[$j];
+        if (!defined($linkname= readlink($slink)) && $! != &ENOENT) {
+            &pr("warning: $slink is supposed to be a slave symlink to\n".
+                " $altdir/$sname, or nonexistent; however, readlink failed: $!");
+        } elsif ($linkname ne "$altdir/$sname") {
+            unlink("$slink.dpkg-tmp") || $! == &ENOENT ||
+                &quit("unable to ensure $slink.dpkg-tmp nonexistent: $!");
+            symlink("$altdir/$sname","$slink.dpkg-tmp") ||
+                &quit("unable to make $slink.dpkg-tmp a symlink to $altdir/$sname: $!");
+            rename("$slink.dpkg-tmp",$slink) ||
+                &quit("unable to install $slink.dpkg-tmp as $slink: $!");
+        }
+        $spath= $slavepath{$bestnum,$j};
+        unlink("$altdir/$sname.dpkg-tmp") || $! == &ENOENT ||
+            &quit("unable to ensure $altdir/$sname.dpkg-tmp nonexistent: $!");
+        if ($spath eq '') {
+            &pr("Removing $sname ($slink), not appropriate with $best.");
+            unlink("$altdir/$sname") || $! == &ENOENT ||
+                &quit("unable to remove $altdir/$sname: $!");
+        } else {
+            if (defined($linkname= readlink("$altdir/$sname")) && $linkname eq $spath) {
+                &pr("Leaving $sname ($slink) pointing to $spath.");
+            } else {
+                &pr("Updating $sname ($slink) to point to $spath.");
+            }
+            symlink("$spath","$altdir/$sname.dpkg-tmp") ||
+                &quit("unable to make $altdir/$sname.dpkg-tmp a symlink to $spath: $!");
+            rename("$altdir/$sname.dpkg-tmp","$altdir/$sname") ||
+                &quit("unable to install $altdir/$sname.dpkg-tmp as $altdir/$sname: $!");
+        }
+    }
+}
+
+sub pr { print(STDOUT "@_\n") || &quit("error writing stdout: $!"); }
+sub paf {
+    $_[0] =~ m/\n/ && &quit("newlines prohibited in update-alternatives files ($_[0])");
+    print(AF "$_[0]\n") || &quit("error writing stdout: $!");
+}
+sub gl {
+    $!=0; $_= <AF>;
+    length($_) || &quit("error or eof reading $admindir/$name for $_[0] ($!)");
+    s/\n$// || &badfmt("missing newline after $_[0]");
+    $_;
+}
+sub badfmt {
+    &quit("internal error: $admindir/$name corrupt: $_[0]");
+}
+
+exit(0);
diff --git a/scripts/update-rc.d.8 b/scripts/update-rc.d.8
new file mode 100644 (file)
index 0000000..3ed3d90
--- /dev/null
@@ -0,0 +1,79 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH UPDATE\-RC.D 8 "29th November 1995" "Debian Project" "Debian/GNU Linux"
+.SH NAME
+update\-rc.d \- install and remove System-V style init script links
+.SH SYNOPSIS
+.B update\-rc.d
+.I <basename>
+\&remove
+.LP
+.B update-rc.d
+.I <basename>
+\&defaults
+.RI [ " <codenumber> " | " <startcodenumber>" " " "<stopcodenumber> " ]
+.LP
+.B update-rc.d
+.I <basename>
+\&start | stop
+.I <codenumber> <runlevel>
+.RI [ " <runlevel> " [ " <runlevel> " [ ... ]]]
+\&.
+.SH DESCRIPTION
+This manual page explains the Debian
+.B "update-rc.d"
+System-V init script link utility.  It should be used when installing and
+removing init scripts on a Debian system.
+
+.SH REMOVING SCRIPTS
+When invoked with the
+.I remove
+option, update-rc.d removes the script and links to the script for the package
+.RI "" <basename> .
+It first finds and removes the script in
+.B /etc/init.d/
+and then removes all links to the script in
+.RB "" /etc/rc[0123456].d/ .
+
+.SH INSTALLING SCRIPTS
+When run with either the
+.RI "" defaults ", " start ", or " stop
+options, update-rc.d makes links pointing to the script in
+.RB "" /etc/init.d/ .
+The script must be installed before update-rc.d is run.
+The
+.I <codenumber>
+arguments specify the order in which the script will be executed.
+When
+.B init
+changes runlevels it executes the scripts in the order of their
+.I codenumber
+from lowest to highest.
+
+The
+.I <runlevel>
+arguments specify the runlevels that the script will be run in.
+As many as seven runlevels (0-6) may be specified.
+The last runlevel must be followed by a period.
+
+When invoked with the
+.I defaults
+option the start runlevels are 
+.B 2 3 4 5
+and the stop runlevels are
+.RB "" "0 1 2 3 4 5 6" .
+If neither
+.I <codenumber>
+or
+.I <startcodenumber>
+and
+.I <stopcodenumber>
+are specified, then the stop and start codenumbers default to 20.
+
+.SH FILES
+.B /etc/init.d/
+.bl
+.B /etc/rc[0123456].d/
+
+.SH "SEE ALSO"
+.BR init (1),
+.BR inittab (1),
diff --git a/scripts/update-rc.d.sh b/scripts/update-rc.d.sh
new file mode 100755 (executable)
index 0000000..d471cc1
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# Usage:
+#  update-rc.d <basename> remove
+#  update-rc.d <basename> [options]
+# Options are:
+#  start <codenumber> <runlevel> <runlevel> <runlevel> .
+#  stop  <codenumber> <runlevel> <runlevel> <runlevel> .
+#  defaults [<codenumber> | <startcode> <stopcode>]
+#   (means       start <startcode> 2 3 4 5
+#    as well as  stop <stopcode> 0 1 2 3 4 5 6
+#    <codenumber> defaults to 20)
+
+set -e
+cd /etc
+
+initd='init.d'
+
+usage () { echo >&2 "\
+update-rc.d: error: $1.
+usage: update-rc.d <basename> remove
+       update-rc.d <basename> defaults [<cn> | <scn> <kcn>]
+       update-rc.d <basename> start|stop <cn> <r> <r> .  ..."; exit 1 }
+
+getinode () {
+       inode="`ls -Li1 \"$1\" | sed -e 's/^ *//; s/ .*//'`"
+}
+
+if [ $# -lt 2 ]; then usage "too few arguments"; fi
+bn="$1"; shift
+
+if [ xremove = "x$1" ]; then
+       if [ $# != 1 ]; then usage "remove must be only action"; fi
+       if [ -f "$initd/$bn" ]; then
+               echo >&2 "update-rc.d: error: /etc/$initd/$bn exists during rc.d purge."
+               exit 1
+       fi
+       echo " Removing any system startup links to /etc/$initd/$bn ..."
+       trap 'rm -f "$initd/$bn"' 0
+       touch "$initd/$bn"
+       getinode "$initd/$bn"
+       own="$inode"
+       for f in rc?.d/[SK]*; do
+               getinode "$f"
+               if [ "x$inode" = "x$own" ]; then
+                       rm "$f";
+                       echo "   $f"
+               fi
+       done
+       exit 0
+elif [ xdefaults = "x$1" ]; then
+       if [ $# = 1 ]; then sn=20; kn=20;
+       elif [ $# = 2 ]; then sn="$2"; kn="$2";
+       elif [ $# = 3 ]; then sn="$2"; kn="$3";
+       else usage "defaults takes only one or two codenumbers"; fi
+       set start "$sn" 2 3 4 5 . stop "$kn" 0 1 6 .
+elif ! [ xstart = "x$1" -o xstop = "x$1" ]; then
+       usage "unknown mode or add action $1"
+fi
+
+if ! [ -f "$initd/$bn" ]; then
+       echo >&2 "update-rc.d: warning /etc/$initd/$bn doesn't exist during rc.d setup."
+       exit 0
+fi
+
+getinode "$initd/$bn"
+own="$inode"
+for f in rc?.d/[SK]*; do
+       getinode "$f"
+       if [ "x$inode" = "x$own" ]; then
+               echo " System startup links pointing to /etc/$initd/$bn already exist."
+               exit 0
+       fi
+done
+
+echo " Adding system startup links pointing to /etc/$initd/$bn ..."
+while [ $# -ge 3 ]; do
+       if [ xstart = "x$1" ]; then ks=S
+       elif [ xstop = "x$1" ]; then ks=K
+       else usage "unknown action $1"; fi
+       number="$2"
+       shift; shift
+       while [ $# -ge 1 ]; do
+               case "$1" in
+               .)
+                       break
+                       ;;
+               ?)
+                       ln -s "../$initd/$bn" "rc$1.d/$ks$number$bn"
+                       echo "   rc$1.d/$ks$number$bn -> ../$initd/$bn"
+                       shift
+                       continue
+                       ;;
+               esac
+               usage 'runlevel is more than one character (forgotten . ?)'
+       done
+       shift
+done
+
+if [ $# != 0 ]; then
+       usage "surplus arguments, but not enough for an add action: $*"
+fi
+
+exit 0
diff --git a/split/Makefile.in b/split/Makefile.in
new file mode 100644 (file)
index 0000000..8cdeaf0
--- /dev/null
@@ -0,0 +1,80 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+dpkglibdir = $(libdir)/dpkg
+datadir = /var/lib/dpkg
+partsdir = $(datadir)/parts
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+perlpath = @perlpath@
+
+SRC = main.c split.c info.c queue.c join.c
+OBJ = main.o split.o info.o queue.o join.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib -ldpkg $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+
+.SUFFIXES:     .c .o .pl
+
+.c.o:
+               $(CC) $(ALL_CFLAGS) -c $<
+
+.pl:
+               sed <$@.pl 's:^#!/usr/bin/perl:#!$(perlpath):' \
+                 | ../insert-version.pl >$@.new
+               chmod +x $@.new
+               mv $@.new $@
+
+all:           dpkg-split mksplit
+
+dpkg-split:    $(OBJ) ../lib/libdpkg.a
+               $(CC) $(LDFLAGS) -o dpkg-split $(OBJ) $(LIBS)
+
+split.o:       split.c
+               $(CC) -DMKSPLITSCRIPT=\"$(dpkglibdir)/mksplit\" $(ALL_CFLAGS) -c $<
+
+$(OBJ):                                        dpkg-split.h ../config.h ../include/dpkg.h
+build.o split.o queue.o join.o main.o: ../include/dpkg-db.h
+info.o extract.o main.o:               ../include/myopt.h
+main.o:                                        ../version.h
+
+clean:
+               rm -f *.o core dpkg-split
+
+distclean:     clean
+               rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:       all
+               $(INSTALL_PROGRAM) -s dpkg-split $(bindir)/dpkg-split
+               $(INSTALL_PROGRAM) mksplit $(dpkglibdir)/mksplit
+#              $(INSTALL_DATA) dpkg-split.8 $(man8dir)/dpkg-split.$(man8)
diff --git a/split/debugmake b/split/debugmake
new file mode 100755 (executable)
index 0000000..53497bc
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -O0' LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
diff --git a/split/dpkg-split.8 b/split/dpkg-split.8
new file mode 100644 (file)
index 0000000..399868d
--- /dev/null
@@ -0,0 +1,19 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH DPKG\-SPLIT 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+dpkg\-split \- Debian multipart package manipulation tool
+.SH DESCRIPTION
+.B dpkg\-split
+does not have a useful man page.  Please do not report this as a bug,
+as this has already been done many times.
+
+Instead, if you are a competent and accurate writer and are willing to
+spend the time reading the source code and writing good manpages
+please write a better man page than this one.
+
+Type
+.B dpkg\-split \-\-help
+for a brief summary of how to use dpkg.
+
+.SH AUTHOR
+Ian Jackson <ijackson@gnu.ai.mit.edu>.
diff --git a/split/dpkg-split.h b/split/dpkg-split.h
new file mode 100644 (file)
index 0000000..7caee53
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * dpkg-split.h - external definitions for this program
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_SPLIT_H
+#define DPKG_SPLIT_H
+
+typedef void dofunction(const char *const *argv);
+dofunction do_split, do_join, do_info, do_auto, do_queue, do_discard;
+
+struct partinfo {
+  const char *filename;
+  const char *fmtversion;
+  const char *package;
+  const char *version;
+  const char *md5sum;
+  unsigned long orglength;
+  int thispartn, maxpartn;
+  unsigned long maxpartlen;
+  unsigned long thispartoffset;
+  unsigned long thispartlen;
+  unsigned long headerlen; /* size of header in part file */
+  unsigned long filesize;
+};
+
+struct partqueue {
+  struct partqueue *nextinqueue;
+  struct partinfo info;
+  /* only fields filename, md5sum, maxpartlen, thispartn, maxpartn
+   * are valid; the rest are null.  If the file is not named correctly
+   * to be a part file md5sum is null too and the numbers are zero.
+   */
+};
+
+extern dofunction *action;
+extern const struct cmdinfo *cipaction;
+extern long maxpartsize;
+extern const char *depotdir, *outputfile;
+extern struct partqueue *queue;
+extern int npquiet, msdos;
+
+void rerr(const char *fn) NONRETURNING;
+void rerreof(FILE *f, const char *fn) NONRETURNING;
+void print_info(const struct partinfo *pi);
+struct partinfo *read_info(FILE *partfile, const char *fn, struct partinfo *ir);
+
+void scandepot(void);
+void reassemble(struct partinfo **partlist, const char *outputfile);
+void mustgetpartinfo(const char *filename, struct partinfo *ri);
+void addtopartlist(struct partinfo**, struct partinfo*, struct partinfo *refi);
+
+#define PARTMAGIC         "!<arch>\ndebian-split    "
+#define HEADERALLOWANCE    1024
+
+#endif /* DPKG_SPLIT_H */
diff --git a/split/info.c b/split/info.c
new file mode 100644 (file)
index 0000000..fcc36d2
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * info.c - information about split archives
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <ar.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-split.h"
+
+static unsigned long unsignedlong(const char *value, const char *fn, const char *what) {
+  unsigned long r;
+  char *endp;
+
+  r= strtoul(value,&endp,10);
+  if (*endp)
+    ohshit("file `%.250s' is corrupt - bad digit (code %d) in %s",fn,*endp,what);
+  return r;
+}
+
+static unsigned long parseheaderlength(const char *inh, size_t len,
+                                       const char *fn, const char *what) {
+  char lintbuf[15];
+
+  if (memchr(inh,0,len))
+    ohshit("file `%.250s' is corrupt - %.250s length contains nulls",fn,what);
+  assert(sizeof(lintbuf) > len);
+  memcpy(lintbuf,inh,len);
+  lintbuf[len]= ' ';
+  *strchr(lintbuf,' ')= 0;
+  return unsignedlong(lintbuf,fn,what);
+}
+
+static char *nextline(char **ripp, const char *fn, const char *what) {
+  char *newline, *rip;
+
+  rip= *ripp;
+  if (!rip) ohshit("file `%.250s' is corrupt - %.250s missing",fn,what);
+  newline= strchr(rip,'\n');
+  if (!newline)
+    ohshit("file `%.250s' is corrupt - missing newline after %.250s",fn,what);
+  *ripp= newline+1;
+  while (newline > rip && isspace(newline[-1])) newline--;
+  *newline= 0;
+  return rip;
+}
+
+struct partinfo *read_info(FILE *partfile, const char *fn, struct partinfo *ir) {
+  /* returns info (nfmalloc'd) if was an archive part and we read it, 0 if it wasn't */
+  static char *readinfobuf= 0;
+  static int readinfobuflen= 0;
+
+  unsigned long thisilen, templong;
+  char magicbuf[sizeof(PARTMAGIC)-1], *rip, *partnums, *slash;
+  struct ar_hdr arh;
+  int c;
+  struct stat stab;
+  
+  if (fread(magicbuf,1,sizeof(PARTMAGIC)-1,partfile) != sizeof(PARTMAGIC)-1)
+    if (ferror(partfile)) rerr(fn); else return 0;
+  if (memcmp(magicbuf,PARTMAGIC,sizeof(magicbuf))) return 0;
+  if (fseek(partfile,-sizeof(arh.ar_name),SEEK_CUR))
+    ohshite("unable to seek back");
+  
+  if (fread(&arh,1,sizeof(arh),partfile) != sizeof(arh)) rerreof(partfile,fn);
+  if (memcmp(arh.ar_fmag,ARFMAG,sizeof(arh.ar_fmag)))
+    ohshit("file `%.250s' is corrupt - bad magic at end of first header",fn);
+  thisilen= parseheaderlength(arh.ar_size,sizeof(arh.ar_size),fn,"info length");
+  if (thisilen >= readinfobuflen) {
+    readinfobuflen= thisilen+1;
+    readinfobuf= m_realloc(readinfobuf,readinfobuflen);
+  }
+  if (fread(readinfobuf,1,thisilen,partfile) != thisilen) rerreof(partfile,fn);
+  if (thisilen & 1) {
+    c= getc(partfile);  if (c==EOF) rerreof(partfile,fn);
+    if (c != '\n')
+      ohshit("file `%.250s' is corrupt - bad padding character (code %d)",fn,c);
+  }
+  readinfobuf[thisilen]= 0;
+  if (memchr(readinfobuf,0,thisilen))
+    ohshit("file `%.250s' is corrupt - nulls in info section",fn);
+
+  ir->filename= fn;
+
+  rip= readinfobuf;
+  ir->fmtversion= nfstrsave(nextline(&rip,fn,"format version number"));
+  if (strcmp(ir->fmtversion,SPLITVERSION))
+    ohshit("file `%.250s' is format version `%.250s' - you need a newer " SPLITTER,
+           fn,ir->fmtversion);
+
+  ir->package= nfstrsave(nextline(&rip,fn,"package name"));
+  ir->version= nfstrsave(nextline(&rip,fn,"package version number"));
+  ir->md5sum= nfstrsave(nextline(&rip,fn,"package file MD5 checksum"));
+  if (strlen(ir->md5sum) != 32 ||
+      strspn(ir->md5sum,"0123456789abcdef") != 32)
+    ohshit("file `%.250s' is corrupt - bad MD5 checksum `%.250s'",fn,ir->md5sum);
+
+  ir->orglength= unsignedlong(nextline(&rip,fn,"total length"),fn,"total length");
+  ir->maxpartlen= unsignedlong(nextline(&rip,fn,"part offset"),fn,"part offset");
+  
+  partnums= nextline(&rip,fn,"part numbers");
+  slash= strchr(partnums,'/');
+  if (!slash) ohshit("file `%.250s' is corrupt - no slash between part numbers",fn);
+  *slash++= 0;
+
+  templong= unsignedlong(slash,fn,"number of parts");
+  if (templong <= 0 || templong > INT_MAX)
+    ohshit("file `%.250s' is corrupt - bad number of parts",fn);
+  ir->maxpartn= templong;
+  templong= unsignedlong(partnums,fn,"parts number");
+  if (templong <= 0 || templong > ir->maxpartn)
+    ohshit("file `%.250s' is corrupt - bad part number",fn);
+  ir->thispartn= templong;
+
+  if (fread(&arh,1,sizeof(arh),partfile) != sizeof(arh)) rerreof(partfile,fn);
+  if (memcmp(arh.ar_fmag,ARFMAG,sizeof(arh.ar_fmag)))
+    ohshit("file `%.250s' is corrupt - bad magic at end of second header",fn);
+  if (strncmp(arh.ar_name,"data",4))
+    ohshit("file `%.250s' is corrupt - second member is not data member",fn);
+
+  ir->thispartlen= parseheaderlength(arh.ar_size,sizeof(arh.ar_size),fn,"data length");
+  ir->thispartoffset= (ir->thispartn-1)*ir->maxpartlen;
+
+  if (ir->maxpartn != (ir->orglength+ir->maxpartlen-1)/ir->maxpartlen)
+    ohshit("file `%.250s' is corrupt - wrong number of parts for quoted sizes",fn);
+  if (ir->thispartlen !=
+      (ir->thispartn == ir->maxpartn
+       ? ir->orglength - ir->thispartoffset : ir->maxpartlen))
+    ohshit("file `%.250s' is corrupt - size is wrong for quoted part number",fn);
+
+  ir->filesize= (SARMAG +
+                 sizeof(arh) + thisilen + (thisilen&1) +
+                 sizeof(arh) + ir->thispartlen + (ir->thispartlen&1));
+
+  if (fstat(fileno(partfile),&stab)) ohshite("unable to fstat part file `%.250s'",fn);
+  if (S_ISREG(stab.st_mode)) {
+    /* Don't do this check if it's coming from a pipe or something.  It's
+     * only an extra sanity check anyway.
+     */
+    if (stab.st_size < ir->filesize)
+      ohshit("file `%.250s' is corrupt - too short",fn);
+  }
+
+  ir->headerlen= SARMAG + sizeof(arh) + thisilen + (thisilen&1) + sizeof(arh);
+    
+  return ir;
+}  
+
+void mustgetpartinfo(const char *filename, struct partinfo *ri) {
+  FILE *part;
+  
+  part= fopen(filename,"r");
+  if (!part) ohshite("cannot open archive part file `%.250s'",filename);
+  if (!read_info(part,filename,ri))
+    ohshite("file `%.250s' is not an archive part",filename);
+  fclose(part);
+}
+
+void print_info(const struct partinfo *pi) {
+  printf("%s:\n"
+         "    Part format version:            %s\n"
+         "    Part of package:                %s\n"
+         "        ... version:                %s\n"
+         "        ... MD5 checksum:           %s\n"
+         "        ... length:                 %lu bytes\n"
+         "        ... split every:            %lu bytes\n"
+         "    Part number:                    %d/%d\n"
+         "    Part length:                    %lu bytes\n"
+         "    Part offset:                    %lu bytes\n"
+         "    Part file size (used portion):  %lu bytes\n\n",
+         pi->filename,
+         pi->fmtversion,
+         pi->package,
+         pi->version,
+         pi->md5sum,
+         pi->orglength,
+         pi->maxpartlen,
+         pi->thispartn,
+         pi->maxpartn,
+         pi->thispartlen,
+         pi->thispartoffset,
+         pi->filesize);
+}
+
+void do_info(const char *const *argv) {
+  const char *thisarg;
+  struct partinfo *pi, ps;
+  FILE *part;
+
+  if (!*argv) badusage("--info requires one or more part file arguments");
+  
+  while ((thisarg= *argv++)) {
+    part= fopen(thisarg,"r");
+    if (!part) ohshite("cannot open archive part file `%.250s'",thisarg);
+    pi= read_info(part,thisarg,&ps);
+    fclose(part);
+    if (pi) {
+      print_info(pi);
+    } else {
+      printf("file `%s' is not an archive part\n",thisarg);
+    }
+    if (ferror(stdout)) werr("stdout");
+  }
+}
diff --git a/split/join.c b/split/join.c
new file mode 100644 (file)
index 0000000..9e99f64
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * join.c - joining
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-split.h"
+
+void reassemble(struct partinfo **partlist, const char *outputfile) {
+  FILE *output, *input;
+  void *buffer;
+  struct partinfo *pi;
+  int i,nr;
+  long buffersize;
+
+  printf("Putting package %s together from %d parts: ",
+         partlist[0]->package,partlist[0]->maxpartn);
+  
+  buffersize= partlist[0]->maxpartlen;
+  for (i=0; i<partlist[0]->maxpartn; i++)
+    if (partlist[0]->headerlen > buffersize) buffersize= partlist[0]->headerlen;
+  buffer= m_malloc(partlist[0]->maxpartlen);
+  output= fopen(outputfile,"w");
+  if (!output) ohshite("unable to open output file `%.250s'",outputfile);
+  for (i=0; i<partlist[0]->maxpartn; i++) {
+    pi= partlist[i];
+    input= fopen(pi->filename,"r");
+    if (!input) ohshite("unable to (re)open input part file `%.250s'",pi->filename);
+    assert(pi->headerlen <= buffersize);
+    nr= fread(buffer,1,pi->headerlen,input);
+    if (nr != pi->headerlen) rerreof(input,pi->filename);
+    assert(pi->thispartlen <= buffersize);
+    printf("%d ",i+1);
+    nr= fread(buffer,1,pi->thispartlen,input);
+    if (nr != pi->thispartlen) rerreof(input,pi->filename);
+    if (pi->thispartlen & 1)
+      if (getc(input) == EOF) rerreof(input,pi->filename);
+    if (ferror(input)) rerr(pi->filename);
+    fclose(input);
+    nr= fwrite(buffer,1,pi->thispartlen,output);
+    if (nr != pi->thispartlen) werr(outputfile);
+  }
+  if (fclose(output)) werr(outputfile);
+  printf("done\n");
+}
+
+
+void addtopartlist(struct partinfo **partlist,
+                   struct partinfo *pi, struct partinfo *refi) {
+  int i;
+  
+  if (strcmp(pi->package,refi->package) ||
+      strcmp(pi->version,refi->version) ||
+      strcmp(pi->md5sum,refi->md5sum) ||
+      pi->orglength != refi->orglength ||
+      pi->maxpartn != refi->maxpartn ||
+      pi->maxpartlen != refi->maxpartlen) {
+    print_info(pi);
+    print_info(refi);
+    ohshit("files `%.250s' and `%.250s' are not parts of the same file",
+           pi->filename,refi->filename);
+  }
+  i= pi->thispartn-1;
+  if (partlist[i])
+    ohshit("there are several versions of part %d - at least `%.250s' and `%.250s'",
+           pi->thispartn, pi->filename, partlist[i]->filename);
+  partlist[i]= pi;
+}
+
+void do_join(const char *const *argv) {
+  char *p;
+  const char *thisarg;
+  struct partqueue *pq;
+  struct partinfo *refi, *pi, **partlist;
+  int i;
+  
+  assert(!queue);
+  if (!*argv) badusage("--join requires one or more part file arguments");
+  while ((thisarg= *argv++)) {
+    pq= nfmalloc(sizeof(struct partqueue));
+
+    mustgetpartinfo(thisarg,&pq->info);
+    
+    
+    pq->nextinqueue= queue;
+    queue= pq;
+  }
+  refi= 0;
+  for (pq= queue; pq; pq= pq->nextinqueue)
+    if (!refi || pq->info.thispartn < refi->thispartn) refi= &pq->info;
+  assert(refi);
+  partlist= nfmalloc(sizeof(struct partinfo*)*refi->maxpartn);
+  for (i=0; i<refi->maxpartn; i++) partlist[i]= 0;
+  for (pq= queue; pq; pq= pq->nextinqueue) {
+    pi= &pq->info;
+    addtopartlist(partlist,pi,refi);
+  }
+  for (i=0; i<refi->maxpartn; i++) {
+    if (!partlist[i]) ohshit("part %d is missing",i+1);
+  }
+  if (!outputfile) {
+    p= nfmalloc(strlen(refi->package)+1+strlen(refi->version)+sizeof(DEBEXT));
+    strcpy(p,refi->package);
+    strcat(p,"-");
+    strcat(p,refi->version);
+    strcat(p,DEBEXT);
+    outputfile= p;
+  }
+  reassemble(partlist,outputfile);
+}
diff --git a/split/junk b/split/junk
new file mode 100644 (file)
index 0000000..d71a8cb
--- /dev/null
@@ -0,0 +1,36 @@
+  struct partqueue *backinpackage; /* circular doubly linked list of     */
+  struct partqueue *nextinpackage; /*  parts of a particular split file  */
+                                   /*  in ascending order of part number */
+ /* singly linked list of all files in depot */
+    pq->nextinpackage= pq->backinpackage= 0;
+
+    for (search= queue;
+         search && !(!strcmp(pq->info.md5sum,search->info.md5sum) &&
+                     pq->info.maxpartlen == search->info.maxpartlen);
+         search= search->next);
+    if (search) {
+      /* insert after search */
+      while (!(search == search->nextinpackage ||
+               (search->info.thispartn < search->nextinpackage->info.thispartn ?
+                (search->info.thispartn <= pq->info.thispartn &&
+                 pq->info.thispartn < search->nextinpackage->info.thispartn) :
+                (search->info.thispartn <= pq->info.thispartn ||
+                 search->nextinpackage->info.thispartn > pq->info.thispartn))))
+        search= search->nextinpackage;
+      if (search->info.maxpartn != pq->info.maxpartn)
+        ohshit("inconsistency in parts depot - "
+               "md5sum `%s' part length %lu has both %d and %d parts",
+               pq->info.md5sum, pq->info.maxpartlen, pq->info.maxpartn,
+               search->info.maxpartn);
+      if (search->info.thispartn == pq->info.thispartn)
+        ohshit("inconsistency in parts depot - two instances of "
+               "md5sum `%s' part length %ld part %d/%d",
+               pq->info.md5sum, pq->info.maxpartlen, pq->info.thispartn,
+               pq->info.maxpartn);
+      pq->nextinpackage= search->nextinpackage;
+      pq->backinpackage= search;
+      pq->nextinpackage->backinpackage= pq;
+      pq->backinpackage->nextinpackage= pq;
+    } else {
+      pq->nextinpackage= pq->backinpackage= pq;
+    }
diff --git a/split/magic b/split/magic
new file mode 100644 (file)
index 0000000..b4819a6
--- /dev/null
@@ -0,0 +1,5 @@
+0      string          !<arch>         archive
+>8     string          debian-binary   - Debian binary package
+>8     string          debian-split    - part of multipart Debian package
+>8     string          __.SYMDEF       random library
+>8     string          
diff --git a/split/main.c b/split/main.c
new file mode 100644 (file)
index 0000000..0864535
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * main.c - main program
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "version.h"
+#include "myopt.h"
+
+#include "dpkg-split.h"
+
+static void printversion(void) {
+  if (!fputs
+      ("Debian GNU/Linux `" SPLITTER "' package archive split/join tool;\n"
+       "version " DPKG_VERSION_ARCH
+       ".  Copyright (C) 1994,1995 Ian Jackson.  This is free\n"
+       "software; see the GNU General Public Licence version 2 or later for copying\n"
+       "conditions.  There is NO warranty.  See dpkg-split --licence for details.\n",
+       stderr)) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs("\
+Usage: " SPLITTER " -s|--split <file> [<prefix>]     Split an archive.\n\
+       " SPLITTER " -j|--join <part> <part> ...      Join parts together.\n\
+       " SPLITTER " -I|--info <part> ...             Display info about a part.\n\
+       " SPLITTER " -h|--help|--version|--licence    Show help/version/licence.\n\
+\n\
+       " SPLITTER " -a|--auto -o <complete> <part>   Auto-accumulate parts.\n\
+       " SPLITTER " -l|--listq                       List unmatched pieces.\n\
+       " SPLITTER " -d|--discard [<filename> ...]    Discard unmatched pieces.\n\
+\n\
+Options:  --depotdir <directory>  (default is /var/lib/dpkg/parts)\n\
+          -S|--partsize <size>    (in Kb, for -s, default is 450)\n\
+          -o|--output <file>      (for -j, default is <package>-<version>.deb)\n\
+          -Q|--npquiet            (be quiet when -a is not a part)\n\
+          --msdos                 (generate 8.3 filenames)\n\
+\n\
+Exit status: 0 = OK;  1 = -a is not a part;  2 = trouble!\n",
+             stderr)) werr("stderr");
+}
+
+const char thisname[]= SPLITTER;
+const char printforhelp[]= "Type " SPLITTER " --help for help.";
+
+dofunction *action=0;
+const struct cmdinfo *cipaction=0;
+long maxpartsize= SPLITPARTDEFMAX;
+const char *depotdir= ADMINDIR "/" PARTSDIR, *outputfile= 0;
+struct partqueue *queue= 0;
+int npquiet= 0, msdos= 0;
+
+void rerr(const char *fn) {
+  ohshite("error reading %s",fn);
+}
+
+void rerreof(FILE *f, const char *fn) {
+  if (ferror(f)) ohshite("error reading %.250s",fn);
+  ohshit("unexpected end of file in %.250s",fn);
+}
+
+static void helponly(const struct cmdinfo *cip, const char *value) {
+  usage(); exit(0);
+}
+static void versiononly(const struct cmdinfo *cip, const char *value) {
+  printversion(); exit(0);
+}
+
+static void setaction(const struct cmdinfo *cip, const char *value);
+
+static void setpartsize(const struct cmdinfo *cip, const char *value) {
+  long newpartsize;
+  char *endp;
+
+  newpartsize= strtol(value,&endp,10);
+  if (newpartsize <= 0 || newpartsize > (INT_MAX >> 10))
+    badusage("part size is far too large or is not positive");
+
+  maxpartsize= newpartsize << 10;
+  if (maxpartsize <= HEADERALLOWANCE)
+    badusage("part size must be at least %dk (to allow for header)",
+             (HEADERALLOWANCE >> 10) + 1);
+}
+
+static dofunction *const dofunctions[]= {
+  do_split,
+  do_join,
+  do_info,
+  do_auto,
+  do_queue,
+  do_discard,
+};
+
+/* NB: the entries using setaction must appear first and be in the
+ * same order as dofunctions:
+ */
+static const struct cmdinfo cmdinfos[]= {
+  { "split",        's',  0,  0, 0,             setaction           },
+  { "join",         'j',  0,  0, 0,             setaction           },
+  { "info",         'I',  0,  0, 0,             setaction           },
+  { "auto",         'a',  0,  0, 0,             setaction           },
+  { "listq",        'l',  0,  0, 0,             setaction           },
+  { "discard",      'd',  0,  0, 0,             setaction           },
+  { "help",         'h',  0,  0, 0,             helponly            },
+  { "version",       0,   0,  0, 0,             versiononly         },
+  { "licence",       0,   0,  0, 0,             showcopyright       }, /* UK spelling */
+  { "license",       0,   0,  0, 0,             showcopyright       }, /* US spelling */
+  { "depotdir",      0,   1,  0, &depotdir,     0                   },
+  { "partsize",     'S',  1,  0, 0,             setpartsize         },
+  { "output",       'o',  1,  0, &outputfile,   0                   },
+  { "npquiet",      'Q',  0,  &npquiet, 0,      0,              1   },
+  { "msdos",         0,   0,  &msdos, 0,        0,              1   },
+  {  0,              0                                              }
+};
+
+static void setaction(const struct cmdinfo *cip, const char *value) {
+  if (cipaction)
+    badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong);
+  cipaction= cip;
+  assert(cip-cmdinfos < sizeof(dofunctions)*sizeof(dofunction*));
+  action= dofunctions[cip-cmdinfos];
+}
+
+int main(int argc, const char *const *argv) {
+  jmp_buf ejbuf;
+  int l;
+  char *p;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  myopt(&argv,cmdinfos);
+  if (!cipaction) badusage("need an action option");
+
+  l= strlen(depotdir);
+  if (l && depotdir[l-1] != '/') {
+    p= nfmalloc(l+2);
+    strcpy(p,depotdir);
+    strcpy(p+l,"/");
+    depotdir= p;
+  }
+
+  setvbuf(stdout,0,_IONBF,0);
+  action(argv);
+
+  if (ferror(stderr)) werr("stderr");
+  
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+  exit(0);
+}
diff --git a/split/mksplit b/split/mksplit
new file mode 100755 (executable)
index 0000000..2ed1770
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/perl --
+# This script is only supposed to be called by dpkg-split.
+# Its arguments are:
+#  <sourcefile> <partsize> <prefix> <totalsize> <partsizeallow> <msdostruncyesno>
+# Stdin is also redirected from the source archive by dpkg-split.
+
+# Copyright (C) 1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@ARGV == 6 || die "mksplit: bad invocation\n";
+
+($sourcefile,$partsize,$prefix,$orgsize,$partsizeallow,$msdos) = @ARGV;
+
+sub output {
+    $!=0; $rv= `$_[0]`; $? && die "mksplit $_[0]: $! $?\n";
+    $rv =~ s/\n$//; $rv =~ s/\s+$//; $rv =~ s/^\s+//;
+    $rv;
+}
+
+$myversion='2.1';
+$csum= &output("md5sum <\"$sourcefile\"");
+$package= &output("dpkg-deb --field \"$sourcefile\" Package");
+$version= &output("dpkg-deb --field \"$sourcefile\" Version");
+$revision= &output("dpkg-deb --field \"$sourcefile\" Package_Revision");
+$version.= "-$revision" if length($revision);
+$nparts=int(($orgsize+$partsize-1)/$partsize);
+$startat=0;
+$showpartnum=1;
+
+$|=1;
+print("Splitting package $package into $nparts parts: ");
+
+$msdos= ($msdos eq 'yes');
+if ($msdos) {
+    $prefixdir= $prefix; $prefixdir =~ s:(/?)/*[^/]+$:$1:;
+    $cleanprefix= $prefix; $cleanprefix =~ s:^.*/+::;
+    $cleanprefix =~ y/-A-Za-z0-9+/-a-za-z0-9x/d;
+}
+
+sub add {
+    $data .=
+        sprintf("%-16s%-12d0     0     100644  %-10d%c\n%s%s",
+                $_[0], time, length($_[1]), 0140, $_[1],
+                (length($_[1]) & 1) ? "\n" : "");
+}                 
+
+while ($startat < $orgsize) {
+    $dsp= "$myversion\n$package\n$version\n$csum\n$orgsize\n$partsize\n".
+          "$showpartnum/$nparts\n";
+    defined($thispartreallen= read(STDIN,$pd,$partsize)) || die "mksplit: read: $!\n";
+    $data= "!<arch>\n";
+    print("$showpartnum ");
+    &add('debian-split',$dsp);
+    &add("data.$showpartnum",$pd);
+    if ($thispartreallen > $partsizeallow) {
+        die "Header is too long, making part too long.  Your package name or version\n".
+            "numbers must be extraordinarily long, or something.  Giving up.\n";
+    }
+    if ($msdos) {
+        $basename= "${showpartnum}of$nparts.$cleanprefix";
+        $basename= substr($basename,0,9);
+        $basename =~ s/^([^.]*)\.(.*)$/$2$1/;
+        $basename= "$prefixdir$basename";
+    } else {
+        $basename= "$prefix.${showpartnum}of$nparts";
+    }
+    open(O,"> $basename.deb") || die("mksplit: open $basename.deb: $!\n");
+    print(O $data) || die("mksplit: write $basename.deb: $!\n");
+    close(O) || die("mksplit: close $basename.deb: $!\n");
+    $startat += $partsize;
+    $showpartnum++;
+}
+print("done\n");
+
+exit(0);
diff --git a/split/mksplit.pl b/split/mksplit.pl
new file mode 100644 (file)
index 0000000..2ed1770
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/perl --
+# This script is only supposed to be called by dpkg-split.
+# Its arguments are:
+#  <sourcefile> <partsize> <prefix> <totalsize> <partsizeallow> <msdostruncyesno>
+# Stdin is also redirected from the source archive by dpkg-split.
+
+# Copyright (C) 1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@ARGV == 6 || die "mksplit: bad invocation\n";
+
+($sourcefile,$partsize,$prefix,$orgsize,$partsizeallow,$msdos) = @ARGV;
+
+sub output {
+    $!=0; $rv= `$_[0]`; $? && die "mksplit $_[0]: $! $?\n";
+    $rv =~ s/\n$//; $rv =~ s/\s+$//; $rv =~ s/^\s+//;
+    $rv;
+}
+
+$myversion='2.1';
+$csum= &output("md5sum <\"$sourcefile\"");
+$package= &output("dpkg-deb --field \"$sourcefile\" Package");
+$version= &output("dpkg-deb --field \"$sourcefile\" Version");
+$revision= &output("dpkg-deb --field \"$sourcefile\" Package_Revision");
+$version.= "-$revision" if length($revision);
+$nparts=int(($orgsize+$partsize-1)/$partsize);
+$startat=0;
+$showpartnum=1;
+
+$|=1;
+print("Splitting package $package into $nparts parts: ");
+
+$msdos= ($msdos eq 'yes');
+if ($msdos) {
+    $prefixdir= $prefix; $prefixdir =~ s:(/?)/*[^/]+$:$1:;
+    $cleanprefix= $prefix; $cleanprefix =~ s:^.*/+::;
+    $cleanprefix =~ y/-A-Za-z0-9+/-a-za-z0-9x/d;
+}
+
+sub add {
+    $data .=
+        sprintf("%-16s%-12d0     0     100644  %-10d%c\n%s%s",
+                $_[0], time, length($_[1]), 0140, $_[1],
+                (length($_[1]) & 1) ? "\n" : "");
+}                 
+
+while ($startat < $orgsize) {
+    $dsp= "$myversion\n$package\n$version\n$csum\n$orgsize\n$partsize\n".
+          "$showpartnum/$nparts\n";
+    defined($thispartreallen= read(STDIN,$pd,$partsize)) || die "mksplit: read: $!\n";
+    $data= "!<arch>\n";
+    print("$showpartnum ");
+    &add('debian-split',$dsp);
+    &add("data.$showpartnum",$pd);
+    if ($thispartreallen > $partsizeallow) {
+        die "Header is too long, making part too long.  Your package name or version\n".
+            "numbers must be extraordinarily long, or something.  Giving up.\n";
+    }
+    if ($msdos) {
+        $basename= "${showpartnum}of$nparts.$cleanprefix";
+        $basename= substr($basename,0,9);
+        $basename =~ s/^([^.]*)\.(.*)$/$2$1/;
+        $basename= "$prefixdir$basename";
+    } else {
+        $basename= "$prefix.${showpartnum}of$nparts";
+    }
+    open(O,"> $basename.deb") || die("mksplit: open $basename.deb: $!\n");
+    print(O $data) || die("mksplit: write $basename.deb: $!\n");
+    close(O) || die("mksplit: close $basename.deb: $!\n");
+    $startat += $partsize;
+    $showpartnum++;
+}
+print("done\n");
+
+exit(0);
diff --git a/split/old-mksplit.sh b/split/old-mksplit.sh
new file mode 100644 (file)
index 0000000..8743f94
--- /dev/null
@@ -0,0 +1,113 @@
+#!/bin/bash
+# This script is only supposed to be called by dpkg-split.
+# Its arguments are:
+#  <sourcefile> <partsize> <prefix> <totalsize> <partsizeallow> <msdostruncyesno>
+# Stdin is also redirected from the source archive by dpkg-split.
+
+# Copyright (C) 1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+set -ex
+
+if [ "$#" != 6 ]; then echo >&2 'Bad invocation of mksplit.sh.'; exit 1; fi
+
+sourcefile="$1"
+partsize="$2"
+prefix="$3"
+orgsize="$4"
+partsizeallow="$5"
+msdos="$6"
+
+myversion=2.1
+csum=`md5sum <"$sourcefile"`
+package="`dpkg-deb --field \"$sourcefile\" Package`"
+version="`dpkg-deb --field \"$sourcefile\" Version`"
+revision="`dpkg-deb --field \"$sourcefile\" Package_Revision`"
+if [ "x$revision" != x ]; then version="$version-$revision"; fi
+nparts=$[($orgsize+$partsize-1)/$partsize]
+startat=0
+partnum=0
+
+td=/tmp/ds$$
+mkdir $td
+ec=1
+trap "rm -r $td; exit $ec" 0
+dsp=$td/debian-split
+
+echo -n "Splitting package $package into $nparts parts: "
+
+if [ yes = "$msdos" ]
+then
+       prefixdir="`dirname \"$prefix\"`"
+       cleanprefix="`basename \"$prefix\" | tr A-Z+ a-zx | tr -dc 0-9a-z-`"
+fi
+
+ar-include () {
+       perl -e '
+               $f= $ARGV[0];
+               (@s= stat(STDIN)) || die "$f: $!";
+                undef $/; read(STDIN,$d,$s[7]) == $s[7] || die "$f: $!";
+               printf("%-16s%-12d0     0     100644  %-10d%c\n%s%s",
+                       $f, time, $s[7], 0140, $d,
+                        ($s[7] & 1) ? "\n" : "") || die "$f: $!";
+                close(STDOUT) || die "$f: $!";
+       ' "$1" <"$td/$1"
+}                 
+
+while [ $startat -lt $orgsize ]
+do
+       showpartnum=$[$partnum+1]
+       echo $myversion >$dsp
+       echo $package >>$dsp
+       echo $version >>$dsp
+       echo $csum >>$dsp
+       echo $orgsize >>$dsp
+       echo $partsize >>$dsp
+       echo $showpartnum/$nparts >>$dsp
+       dd bs=$partsize skip=$partnum count=1 \
+          of=$td/data.$showpartnum \
+        2>&1 | (egrep -v '.* records (in|out)' || true)
+       rm -f $td/part
+       echo -n "$showpartnum "
+       echo '!<arch>' >$td/part
+       ar-include debian-split >>$td/part
+       ar-include data.$showpartnum >>$td/part
+       thispartreallen="`ls -l $td/part | awk '{print $5}'`"
+       if ! [ "$thispartreallen" -le "$partsizeallow" ]
+       then
+               cat >&2 <<END
+
+Header is too long, making part too long.  Your package name or version
+numbers must be extraordinarily long, or something.  Giving up.
+END
+               exit 1
+       fi
+       if [ yes = "$msdos" ]
+       then
+               basename="`echo ${showpartnum}of$nparts.\"$cleanprefix\" | \
+                          dd bs=9 count=1 2>/dev/null | \
+                          sed -e 's/^\([^.]*\)\.\(.*\)$/\2\1/'`"
+               basename="$prefixdir/$basename"
+       else
+               basename="$prefix.${showpartnum}of$nparts"
+       fi
+       mv $td/part $basename.deb
+       startat=$[$startat+$partsize]
+       partnum=$showpartnum
+done
+echo "done"
+
+ec=0
diff --git a/split/queue.c b/split/queue.c
new file mode 100644 (file)
index 0000000..35d0418
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * queue.c - queue management
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Queue, in /var/lib/dpkg/parts, is a plain directory with one
+ * file per part.
+ *
+ * parts are named
+ *  <md5sum>.<maxpartlen>.<thispartn>.<maxpartn>
+ * all numbers in hex
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-split.h"
+
+static int decompose_filename(const char *filename, struct partqueue *pq) {
+  const char *p;
+  char *q;
+
+  if (strspn(filename,"0123456789abcdef") != 32 || filename[32] != '.') return 0;
+  q= nfmalloc(33);
+  memcpy(q,filename,32); q[32]= 0;
+  pq->info.md5sum= q;
+  p= filename+33;
+  pq->info.maxpartlen= strtol(p,&q,16); if (q==p || *q++ != '.') return 0;
+  p=q; pq->info.thispartn= (int)strtol(p,&q,16); if (q==p || *q++ != '.') return 0;
+  p=q; pq->info.maxpartn= (int)strtol(p,&q,16); if (q==p || *q) return 0;
+  return 1;
+}
+
+void scandepot(void) {
+  DIR *depot;
+  struct dirent *de;
+  struct partqueue *pq;
+  char *p;
+
+  assert(!queue);
+  depot= opendir(depotdir);
+  if (!depot) ohshite("unable to read depot directory `%.250s'",depotdir);
+  while ((de= readdir(depot))) {
+    if (de->d_name[0] == '.') continue;
+    pq= nfmalloc(sizeof(struct partqueue));
+    pq->info.fmtversion= pq->info.package= pq->info.version= 0;
+    pq->info.orglength= pq->info.thispartoffset= pq->info.thispartlen= 0;
+    pq->info.headerlen= 0;
+    p= nfmalloc(strlen(depotdir)+strlen(de->d_name)+1);
+    strcpy(p,depotdir);
+    strcat(p,de->d_name);
+    pq->info.filename= p;
+    if (!decompose_filename(de->d_name,pq)) {
+      pq->info.md5sum= 0;
+      pq->info.maxpartlen= pq->info.thispartn= pq->info.maxpartn= 0;
+    }
+    pq->nextinqueue= queue;
+    queue= pq;
+  }
+}
+
+static int partmatches(struct partinfo *pi, struct partinfo *refi) {
+  return (pi->md5sum &&
+          !strcmp(pi->md5sum,refi->md5sum) &&
+          pi->maxpartn == refi->maxpartn &&
+          pi->maxpartlen == refi->maxpartlen);
+}
+
+void do_auto(const char *const *argv) {
+  const char *partfile;
+  struct partinfo *pi, *refi, *npi, **partlist, *otherthispart;
+  struct partqueue *pq;
+  int i, nr, j, ap;
+  FILE *part;
+  void *buffer;
+  char *p, *q;
+
+  if (!outputfile) badusage("--auto requires the use of the --output option");
+  if (!(partfile= *argv++) || *argv)
+    badusage("--auto requires exactly one part file arguments");
+
+  refi= nfmalloc(sizeof(struct partqueue));
+  part= fopen(partfile,"r");
+  if (!part) ohshite("unable to read part file `%.250s'",partfile);
+  if (!read_info(part,partfile,refi)) {
+    if (!npquiet)
+      printf("File `%.250s' is not part of a multipart archive.\n",partfile);
+    if (fclose(stdout)) werr("stdout");
+    exit(1);
+  }
+  fclose(part);
+  scandepot();
+  partlist= nfmalloc(sizeof(struct partinfo*)*refi->maxpartn);
+  for (i=0; i<refi->maxpartn; i++) partlist[i]= 0;
+  for (pq= queue; pq; pq= pq->nextinqueue) {
+    pi= &pq->info;
+    if (!partmatches(pi,refi)) continue;
+    npi= nfmalloc(sizeof(struct partinfo));
+    mustgetpartinfo(pi->filename,npi);
+    addtopartlist(partlist,npi,refi);
+  }
+  /* If we already have a copy of this version we ignore it and prefer the
+   * new one, but we still want to delete the one in the depot, so we
+   * save its partinfo (with the filename) for later.  This also prevents
+   * us from accidentally deleting the source file.
+   */
+  otherthispart= partlist[refi->thispartn-1];
+  partlist[refi->thispartn-1]= refi;
+  for (j=refi->maxpartn-1; j>=0 && partlist[j]; j--);
+
+  if (j>=0) {
+
+    part= fopen(partfile,"r");
+    if (!part) ohshite("unable to reopen part file `%.250s'",partfile);
+    buffer= nfmalloc(refi->filesize);
+    nr= fread(buffer,1,refi->filesize,part);
+    if (nr != refi->filesize) rerreof(part,partfile);
+    if (getc(part) != EOF) ohshit("part file `%.250s' has trailing garbage",partfile);
+    if (ferror(part)) rerr(partfile);
+    fclose(part);
+    p= nfmalloc(strlen(depotdir)+50);
+    q= nfmalloc(strlen(depotdir)+200);
+    sprintf(p,"%st.%lx",depotdir,(long)getpid());
+    sprintf(q,"%s%s.%lx.%x.%x",depotdir,refi->md5sum,
+            refi->maxpartlen,refi->thispartn,refi->maxpartn);
+    part= fopen(p,"w");
+    if (!part) ohshite("unable to open new depot file `%.250s'",p);
+    nr= fwrite(buffer,1,refi->filesize,part);
+    if (nr != refi->filesize) werr(p);
+    if (fclose(part)) werr(p);
+    if (rename(p,q)) ohshite("unable to rename new depot file `%.250s' to `%.250s'",p,q);
+
+    printf("Part %d of package %s filed (still want ",refi->thispartn,refi->package);
+    /* There are still some parts missing. */
+    for (i=0, ap=0; i<refi->maxpartn; i++)
+      if (!partlist[i])
+        printf("%s%d", !ap++ ? "" : i==j ? " and " : ", ", i+1);
+    printf(").\n");
+
+  } else {
+
+    /* We have all the parts. */
+    reassemble(partlist,outputfile);
+
+    /* OK, delete all the parts (except the new one, which we never copied). */
+    partlist[refi->thispartn-1]= otherthispart;
+    for (i=0; i<refi->maxpartn; i++)
+      if (partlist[i])
+        if (unlink(partlist[i]->filename))
+          ohshite("unable to delete used-up depot file `%.250s'",partlist[i]->filename);
+
+  }
+
+  if (ferror(stderr)) werr("stderr");
+}
+
+void do_queue(const char *const *argv) {
+  struct partqueue *pq, *qq;
+  struct partinfo ti;
+  const char *head;
+  struct stat stab;
+  unsigned long bytes;
+  int i;
+
+  if (*argv) badusage("--listq does not take any arguments");
+  scandepot();
+
+  head= "Junk files left around in the depot directory:\n";
+  for (pq= queue; pq; pq= pq->nextinqueue) {
+    if (pq->info.md5sum) continue;
+    fputs(head,stdout); head= "";
+    if (lstat(pq->info.filename,&stab))
+      ohshit("unable to stat `%.250s'",pq->info.filename);
+    if (S_ISREG(stab.st_mode)) {
+      bytes= stab.st_size;
+      printf(" %s (%lu bytes)\n",pq->info.filename,bytes);
+    } else {
+      printf(" %s (not a plain file)\n",pq->info.filename);
+    }
+  }
+  if (!*head) putchar('\n');
+  
+  head= "Packages not yet reassembled:\n";
+  for (pq= queue; pq; pq= pq->nextinqueue) {
+    if (!pq->info.md5sum) continue;
+    mustgetpartinfo(pq->info.filename,&ti);
+    fputs(head,stdout); head= "";
+    printf(" Package %s: part(s) ",ti.package);
+    bytes= 0;
+    for (i=0; i<ti.maxpartn; i++) {
+      for (qq= pq;
+           qq && !(partmatches(&qq->info,&ti) && qq->info.thispartn == i+1);
+           qq= qq->nextinqueue);
+      if (qq) {
+        printf("%d ",i+1);
+        if (lstat(qq->info.filename,&stab))
+          ohshite("unable to stat `%.250s'",qq->info.filename);
+        if (!S_ISREG(stab.st_mode))
+          ohshit("part file `%.250s' is not a plain file",qq->info.filename);
+        bytes+= stab.st_size;
+        qq->info.md5sum= 0; /* don't find this package again */
+      }
+    }
+    printf("(total %lu bytes)\n",bytes);
+  }
+  if (fclose(stdout)) werr("stdout");
+}
+
+enum discardwhich { ds_junk, ds_package, ds_all };
+
+static void discardsome(enum discardwhich which, const char *package) {
+  struct partqueue *pq;
+
+  for (pq= queue; pq; pq= pq->nextinqueue) {
+    switch (which) {
+    case ds_junk:
+      if (pq->info.md5sum) continue;
+      break;
+    case ds_package:
+      if (!pq->info.md5sum || strcasecmp(pq->info.package,package)) continue;
+      break;
+    case ds_all:
+      break;
+    default: internerr("bad discardsome which");
+    }
+    if (unlink(pq->info.filename))
+      ohshite("unable to discard `%.250s'",pq->info.filename);
+    printf("Deleted %s.\n",pq->info.filename);
+  }
+}
+
+void do_discard(const char *const *argv) {
+  const char *thisarg;
+  struct partqueue *pq;
+
+  scandepot();
+  if (*argv) {
+    for (pq= queue; pq; pq= pq->nextinqueue)
+      if (pq->info.md5sum)
+        mustgetpartinfo(pq->info.filename,&pq->info);
+    discardsome(ds_junk,0);
+    while ((thisarg= *argv++)) discardsome(ds_package,thisarg);
+  } else {
+    discardsome(ds_all,0);
+  }
+}
diff --git a/split/split.c b/split/split.c
new file mode 100644 (file)
index 0000000..facdeb0
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * split.c - splitting archives
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-split.h"
+
+void do_split(const char *const *argv) {
+  const char *sourcefile, *prefix;
+  char *palloc;
+  int l, fd;
+  char partsizebuf[30], lengthbuf[30], partsizeallowbuf[30];
+  struct stat stab;
+
+  sourcefile= *argv++;
+  if (!sourcefile)
+    badusage("--split needs a source filename argument");
+  prefix= *argv++;
+  if (prefix && *argv)
+    badusage("--split takes at most a source filename and destination prefix");
+  if (!prefix) {
+    l= strlen(sourcefile);
+    palloc= nfmalloc(l+1);
+    strcpy(palloc,sourcefile);
+    if (!strcmp(palloc+l-(sizeof(DEBEXT)-1),DEBEXT)) {
+      l -= (sizeof(DEBEXT)-1);
+      palloc[l]= 0;
+    }
+    prefix= palloc;
+  }
+  sprintf(partsizebuf,"%ld",maxpartsize-HEADERALLOWANCE);
+  sprintf(partsizeallowbuf,"%ld",maxpartsize);
+  fd= open(sourcefile,O_RDONLY);
+  if (!fd) ohshite("unable to open source file `%.250s'",sourcefile);
+  if (fstat(fd,&stab)) ohshite("unable to fstat source file");
+  if (!S_ISREG(stab.st_mode)) ohshit("source file `%.250s' not a plain file",sourcefile);
+  sprintf(lengthbuf,"%lu",(unsigned long)stab.st_size);
+  m_dup2(fd,0);
+  execl(MKSPLITSCRIPT,MKSPLITSCRIPT,
+        sourcefile,partsizebuf,prefix,lengthbuf,partsizeallowbuf,msdos?"yes":"no",
+        (char*)0);
+  ohshite("unable to exec " MKSPLITSCRIPT);
+}
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..ce5a0ea
--- /dev/null
+++ b/version.h
@@ -0,0 +1 @@
+#define DPKG_VERSION "1.1.4" /* This line modified by Makefile */