--- /dev/null
+ 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.
--- /dev/null
+ 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'.
--- /dev/null
+# 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
--- /dev/null
+(-*- 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.
--- /dev/null
+-*- 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. ]
--- /dev/null
+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'
--- /dev/null
+/* 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
--- /dev/null
+# 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
--- /dev/null
+
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+#! /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
+
--- /dev/null
+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)
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+# 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
--- /dev/null
+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.
--- /dev/null
+#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
--- /dev/null
+.\" 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).
--- /dev/null
+.\" 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).
--- /dev/null
+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 -------
--- /dev/null
+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
--- /dev/null
+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.
+
--- /dev/null
+(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 -------
--- /dev/null
+\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
--- /dev/null
+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.
+
--- /dev/null
+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::
+
--- /dev/null
+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.
+
+
--- /dev/null
+\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
--- /dev/null
+\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:
--- /dev/null
+***************
+*** 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
--- /dev/null
+
+@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
--- /dev/null
+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.
--- /dev/null
+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'.
+ */
+
--- /dev/null
+(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);
+}
--- /dev/null
+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.
--- /dev/null
+# 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)
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+#!/bin/sh
+set -x
+make XCFLAGS='-g -O0' LDFLAGS=-g LIBS='-lefence -L../lib -ldpkg' "$@"
--- /dev/null
+.\" 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.
--- /dev/null
+.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).
+
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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); }
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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() { }
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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 }
+};
--- /dev/null
+/* -*- 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 */
--- /dev/null
+#!/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;
+}
--- /dev/null
+/*
+ * 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"
+};
--- /dev/null
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -O0' LDFLAGS=-g 'EXTERNLIBS= -lncurses_g -lefence' "$@"
--- /dev/null
+.\" 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).
--- /dev/null
+/* -*- 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 */
--- /dev/null
+@@@ 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
--- /dev/null
+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
+
--- /dev/null
+# 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]
--- /dev/null
+{ 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" },
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 }
+};
--- /dev/null
+/*
+ * 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;
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* -*- 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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 $!;
+}
--- /dev/null
+#!/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
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 }
+};
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/* -*- 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+#!/bin/sh
+while cat p; do echo ===================; done
--- /dev/null
+#include <ncurses/curses.h>
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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
--- /dev/null
+#!/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;
+}
--- /dev/null
+#!/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
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+ */
--- /dev/null
+/*
+ * 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--;
+}
--- /dev/null
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -DMDEBUG -O0' LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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++;
+ }
+}
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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 */
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+ { "i386", "i386" },
+ { "i486", "i386" },
+ { "i586", "i386" },
+ { "sparc", "sparc" },
+ { "alpha", "alpha" },
+ { "m68k", "m68k" },
+ { "arm", "arm" },
+ { "ppc", "ppc" },
--- /dev/null
+/*
+ * 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--;
+}
--- /dev/null
+/*
+ * 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,"-");
+ }
+}
--- /dev/null
+#!/bin/sh
+set -x
+make XCFLAGS=-g LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
--- /dev/null
+/*
+ * 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 {...} */
+}
--- /dev/null
+.\" 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>.
--- /dev/null
+.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).
+
+
--- /dev/null
+/*
+ * 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= §ionentries;
+ *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");
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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;
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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");
+}
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+# (-*- 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+.\" 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)
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+# 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 *~ *.~* ./#*#
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+#!/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
--- /dev/null
+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.
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+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.
--- /dev/null
+#!/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
--- /dev/null
+50 floppy Install from a pile of floppy disks.
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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);
--- /dev/null
+# 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'}");
+
--- /dev/null
+# 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;
+
--- /dev/null
+#!/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
--- /dev/null
+# 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
--- /dev/null
+#!/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]"); }
--- /dev/null
+.\" 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.
--- /dev/null
+#!/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:
+
--- /dev/null
+#!/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 $!;
--- /dev/null
+.\" 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.
--- /dev/null
+#!/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;
--- /dev/null
+# -*- 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');
+}
--- /dev/null
+#!/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) {
+ ©perm("$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;
+ }
+}
--- /dev/null
+.\" 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>.
--- /dev/null
+#!/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);
--- /dev/null
+.\" 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>.
--- /dev/null
+#!/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);
--- /dev/null
+.\" 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),
--- /dev/null
+#!/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
--- /dev/null
+# 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)
--- /dev/null
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -O0' LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"
--- /dev/null
+.\" 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>.
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+ 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;
+ }
--- /dev/null
+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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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);
--- /dev/null
+#!/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);
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#define DPKG_VERSION "1.1.4" /* This line modified by Makefile */