1
0
Fork 0

Adding upstream version 1.22.20.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
Daniel Baumann 2025-06-20 21:21:00 +02:00
parent 4edf0f5987
commit 1879661313
Signed by: daniel.baumann
GPG key ID: BCC918A2ABD66424
2130 changed files with 1371224 additions and 0 deletions

1
.dist-vcs-id Normal file
View file

@ -0,0 +1 @@
8243233fc5173110798cbc22711fb4675a356d02

1
.dist-vcs-url Normal file
View file

@ -0,0 +1 @@
https://git.dpkg.org/git/dpkg/dpkg.git

1
.dist-version Normal file
View file

@ -0,0 +1 @@
1.22.20

1
ABOUT-NLS Normal file
View file

@ -0,0 +1 @@
<https://www.gnu.org/software/gettext/manual/html_node/Users.html>

35
AUTHORS Normal file
View file

@ -0,0 +1,35 @@
It is currently maintained by:
Guillem Jover <guillem@debian.org> (2006-)
and has previously been maintained by:
Raphaël Hertzog <hertzog@debian.org> (2008-2015)
Christian Perrier <bubulle@debian.org> (2006-2008)
Frank Lichtenheld <djpig@debian.org> (2006-2009)
Brendan O'Dea <bod@debian.org> (2006-2007)
Scott James Remnant <scott@netsplit.com> (2004-2005)
Adam Heath <doogie@brainfood.com> (2001-2003)
Wichert Akkerman <wakkerma@debian.org> (1999-2003)
Ben Collins <bcollins@debian.org> (1999-2001)
Daniel Jacobowitz <dan@debian.org> (1998)
J.H.M. Dassen (Ray) <jdassen@wi.LeidenUniv.nl> (1998)
James Troup <jjtroup@comp.brad.ac.uk> (1998)
Nils Rennebarth <nils@debian.org> (1998)
Klee Dienes <klee@debian.org> (1997)
Guy Maor <maor@ece.utexas.edu> (1997)
Heiko Schlittermann <hs@schlittermann.de> (1996)
the C implementation of dpkg was originally written and maintained by:
Ian Jackson <ijackson@chiark.greenend.org.uk> (1994-1998)
based on the Perl implementation written and/or maintained by:
Matt Welsh <mdw@sunsite.unc.edu> (1994)
Carl Streeter <streeter@cae.wisc.edu> (1994)
Ian Murdock <imurdock@debian.org> (1994)
Countless other people have contributed to dpkg (see THANKS) and provided
code for which they claim copyright (see debian/copyright). Many thanks
to them all.

339
COPYING Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.
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.)
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.
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.
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
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) <year> <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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 Lesser General
Public License instead of this License.

142180
ChangeLog Normal file

File diff suppressed because it is too large Load diff

16925
ChangeLog.old Normal file

File diff suppressed because it is too large Load diff

264
Makefile.am Normal file
View file

@ -0,0 +1,264 @@
## Process this file with automake to produce Makefile.in
if BUILD_DSELECT
MAYBE_DSELECT = dselect
endif
SUBDIRS = \
lib \
src \
utils \
$(MAYBE_DSELECT) \
scripts \
po \
man \
# EOL
ACLOCAL_AMFLAGS = -I m4
dist_aclocal_DATA = \
m4/dpkg-arch.m4 \
m4/dpkg-build.m4 \
m4/dpkg-compiler.m4 \
m4/dpkg-coverage.m4 \
m4/dpkg-funcs.m4 \
m4/dpkg-headers.m4 \
m4/dpkg-libs.m4 \
m4/dpkg-linker.m4 \
m4/dpkg-progs.m4 \
m4/dpkg-types.m4 \
m4/dpkg-unicode.m4 \
# EOL
dist_pkgdata_DATA = \
data/pie-compile.specs \
data/pie-link.specs \
data/no-pie-compile.specs \
data/no-pie-link.specs \
data/cputable \
data/ostable \
data/abitable \
data/tupletable \
# EOL
dist_doc_DATA = \
doc/README.api \
doc/README.feature-removal-schedule \
# EOL
dist_docspec_DATA = \
doc/spec/build-driver.txt \
doc/spec/frontend-api.txt \
doc/spec/protected-field.txt \
doc/spec/rootless-builds.txt \
doc/spec/triggers.txt \
# EOL
EXTRA_DIST = \
ChangeLog.old \
README.l10n \
autogen \
build-aux/gen-changelog \
build-aux/gen-release \
build-aux/get-vcs-id \
build-aux/get-version \
build-aux/lcov-inject \
build-aux/run-script \
build-aux/test-runner \
doc/coding-style.txt \
debian/README.bug-usertags \
debian/changelog \
debian/control \
debian/copyright \
debian/dpkg-dev.NEWS \
debian/dpkg-dev.docs \
debian/dpkg-dev.install \
debian/dpkg-dev.manpages \
debian/dpkg.alternatives.logrotate \
debian/dpkg.cfg \
debian/dpkg.cron.daily \
debian/dpkg.docs \
debian/dpkg.dpkg-db-backup.service \
debian/dpkg.dpkg-db-backup.timer \
debian/dpkg.install \
debian/dpkg.manpages \
debian/dpkg.postinst \
debian/dpkg.postrm \
debian/dpkg.logrotate \
debian/dpkg.lintian-overrides \
debian/dpkg.lintian-profile \
debian/dselect.cfg \
debian/dselect.docs \
debian/dselect.install \
debian/dselect.lintian-overrides \
debian/dselect.manpages \
debian/dselect.postrm \
debian/libdpkg-dev.install \
debian/libdpkg-dev.manpages \
debian/libdpkg-perl.install \
debian/source/format \
debian/source/lintian-overrides \
debian/not-installed \
debian/rules \
debian/shlibs.default \
debian/shlibs.override \
debian/tests/control \
debian/tests/test-func \
debian/tests/test-func-root \
debian/tests/test-not-root \
debian/tests/test-root \
po/its/polkit.its \
po/its/polkit.loc \
# EOL
.PHONY: doc
doc: doc/Doxyfile
$(DOXYGEN) doc/Doxyfile
doc-clean:
rm -rf doc/html/
# Code coverage support
.PHONY: coverage coverage-clean
if COVERAGE_ENABLED
LCOV_OPTS = --quiet --rc checksum=1 --rc branch_coverage=1
LCOV_CAPTURE_OPTS = $(LCOV_OPTS) --no-recursion \
--directory $(top_builddir)/lib/dpkg \
--directory $(top_builddir)/src/common \
--directory $(top_builddir)/src/deb \
--directory $(top_builddir)/src/split \
--directory $(top_builddir)/src/divert \
--directory $(top_builddir)/src/query \
--directory $(top_builddir)/src/trigger \
--directory $(top_builddir)/src/statoverride \
--directory $(top_builddir)/src/main \
--directory $(top_builddir)/utils \
# EOL
LCOV_INJECT = $(PERL) -i $(top_srcdir)/build-aux/lcov-inject
coverage: all
: # Remove coverage data from any previous run
rm -f *.lcov
find -name '*.gcda' -o -name '*.gcov' | xargs rm -f
: # Initialize data
$(LCOV) $(LCOV_CAPTURE_OPTS) --capture --initial \
--output-file dpkg_base.lcov
: # Run test cases
$(MAKE) -C lib/dpkg check
$(MAKE) -C src check
$(MAKE) -C utils check
: # Merge test coverage data
$(LCOV) $(LCOV_CAPTURE_OPTS) --capture \
--output-file dpkg_test.lcov
$(LCOV) $(LCOV_OPTS) \
--add-tracefile dpkg_base.lcov \
--add-tracefile dpkg_test.lcov \
--output-file dpkg.lcov
: # Generate reports
$(LCOV) $(LCOV_OPTS) --list dpkg.lcov
$(LCOV_GENHTML) $(LCOV_OPTS) \
--legend --title "dpkg $(VERSION) C code coverage" \
--output-directory doc/coverage dpkg.lcov
$(MAKE) -C scripts $@
: # XXX: Inject perl coverage into lcov index files. This is a fragile
: # hack which might break depending on the html output generated.
$(LCOV_INJECT) doc/coverage/index-sort-b.html
$(LCOV_INJECT) doc/coverage/index-sort-f.html
$(LCOV_INJECT) doc/coverage/index-sort-l.html
$(LCOV_INJECT) doc/coverage/index.html
coverage-clean:
rm -rf doc/coverage/
find -name '*.gcno' -o -name '*.gcda' -o \
-name '*.gcov' -o -name '*.lcov' | xargs rm -f
$(MAKE) -C scripts $@
else
coverage:
@echo "Need to reconfigure with --enable-coverage"
coverage-clean:
endif
test_scripts = \
t/po.t \
t/pod.t \
t/pod-spell.t \
t/pod-coverage.t \
t/synopsis.t \
t/minimum-version.t \
t/module-version.t \
t/syntax.t \
t/strict.t \
t/critic.t \
t/codespell.t \
t/shellcheck.t \
t/cppcheck.t \
# EOL
test_data = \
t/codespell/stopwords \
t/cppcheck/cppcheck.supp \
t/critic/perlcriticrc \
# EOL
EXTRA_DIST += \
tests \
$(test_scripts) \
$(test_data) \
# EOL
# We need to use absolute paths here due to strict.t invoking a sub-perl,
# while changing dir to source dir on out-of-tree builds.
TEST_ENV_VARS = \
DPKG_DATADIR=$(abs_top_srcdir)/data \
# EOL
include $(top_srcdir)/build-aux/tap.am
check-local: tap-check
.PHONY: update-po
update-po:
$(MAKE) -C po update-po
$(MAKE) -C scripts/po update-po
$(MAKE) -C dselect/po update-po
$(MAKE) -C man update-po
include $(top_srcdir)/build-aux/cpan.am
# If we create the dist tarball from the git repository, make sure
# that we're not forgetting some files, and we are not storing any symlink
# in the repository (except for the origins/default one) as those degrade
# to regular files due to automake telling tar to dereference them.
#
# XXX: As long as we have the Makefile based functional test suite, we need
# to remove .gitignore files from it, because we are including the entire
# hierarchy in EXTRA_DIST.
dist-hook:
echo $(VERSION) >$(distdir)/.dist-version
echo $(PACKAGE_VCS_URL) >$(distdir)/.dist-vcs-url
echo $(PACKAGE_VCS_ID) >$(distdir)/.dist-vcs-id
find "$(distdir)/tests" -type f -name '.git*' | xargs rm -f
if [ -e .git ]; then \
for file in `git ls-tree -r HEAD | grep ^12 | grep -v t/origins/default`; do \
echo "$$file is a symlink packed as a file on the dist tar" >&2 ; \
exit 1 ; \
done ; \
for file in `git ls-files | grep -vE '\.(git|mailmap)'`; do \
if [ ! -e "$(distdir)/$$file" ]; then \
echo "$$file is missing in $(distdir)" >&2 ; \
exit 1 ; \
fi ; \
done ; \
XDG_CONFIG_HOME= HOME= \
git log -C --stat 1.15.0.. >$(distdir)/ChangeLog; \
fi
clean-local: doc-clean coverage-clean tap-clean

1374
Makefile.in Normal file

File diff suppressed because it is too large Load diff

1
NEWS Normal file
View file

@ -0,0 +1 @@
See debian/changelog for major changes between dpkg releases.

142
README Normal file
View file

@ -0,0 +1,142 @@
dpkg - Debian's package maintenance system
This is the dpkg suite of programs that form the foundation of the Debian's
package management system; on the lower layer there are dpkg-deb and
dpkg-split programs handling the binary formats, and dpkg-source program
handling the source formats; there is a collection of tools to handle building
source packages into binary packages; there is the medium-level and less
user-friendly command-line interface (CLI) in the form of the dpkg command;
and then there is the terminal user interface (TUI) dselect program (which
has gone out of preference in favor of the apt (CLI) and aptitude (TUI)
programs).
The dpkg suite also includes some other programs currently maintained
on external repositories, namely dpkg-repack, dpkg-www, dupload
and debsig-verify.
Releases
--------
The current legacy, stable and development releases can be found at:
<https://deb.debian.org/debian/pool/main/d/dpkg/>
For older releases check:
<https://snapshot.debian.org/package/dpkg/>
Mailing List
------------
The subscription interface and web archives can be found at:
<https://lists.debian.org/debian-dpkg/>
The mailing list address is (no subscription required to post):
debian-dpkg@lists.debian.org
Source Repository
-----------------
The primary repository can be browsed and cloned from:
<https://git.dpkg.org/git/dpkg/dpkg.git>
Building from git source
------------------------
To prepare the dpkg source tree from git before starting the build process
some required software needs to be installed:
GNU autoconf >= 2.60
GNU automake >= 1.11
GNU libtool >= 2.0
GNU autopoint >= 0.19.7 (from GNU gettext)
GNU gettext >= 0.19.7 (only with --enable-nls)
After installing the needed software, and running the following command on
the git tree:
$ ./autogen
the source should be roughly equivalent to the distributed tar source.
To enable translated documentation this software will be needed:
po4a >= 0.59
Building from tar source
------------------------
The minimum software required to configure and build dpkg from a tarball is:
C99 compiler (see doc/coding-style.txt)
perl (see doc/coding-style.txt)
pkgconf
GNU make
To enable optional functionality or programs, this software might be needed:
libmd (used by libdpkg, required if libc is missing digest functions)
libz (from zlib, used instead of gzip command-line tool)
liblzma (from xz utils, used instead of xz command-line tool)
libzstd (from libzstd, used instead of zstd command-line tool)
libbz2 (from bzip2, used instead of bzip2 command-line tool)
libselinux
curses compatible library (needed on --enable-dselect)
To run the test suite («make check» or «make authorcheck» for author tests,
those that might not be pertinent during release builds) the following
software might be needed:
Test::MinimumVersion perl module (optional, author)
Test::Pod perl module (optional)
Test::Pod::Coverage perl module (optional, author)
Test::Spelling perl module (optional, author)
Test::Strict perl module (optional)
Test::Synopsis perl module (optional, author)
Test::Perl::Critic perl module (optional, author)
aspell (optional, author)
aspell-en (optional, author)
codespell (optional, author)
cppcheck (optional, author)
fakeroot (optional)
sop [sqop (from Sequoia-PGP), pgpainless-cli] (optional)
sq (from Sequoia-PGP, optional)
gpg-sq (from Sequoia-PGP, optional), gpg (optional)
i18nspector (optional, author)
shellcheck (optional, author)
To enable additional developer's documentation («make doc») this software
will be needed:
pod2man
doxygen
dot
To enable code coverage («./configure --enable-coverage; make coverage»)
this software is needed:
lcov (from the Linux Test Project)
Devel-Cover perl module
The build process is done by running the usual «./configure; make». To
see all available configuration options please run «./configure --help».
The following configure options might be of interest to disable specific
programs:
--disable-dselect
--disable-start-stop-daemon
--disable-update-alternatives
And the following to disable modifications to the build flags:
--disable-compiler-warnings
--disable-compiler-optimizations
--disable-linker-optimizations

61
README.l10n Normal file
View file

@ -0,0 +1,61 @@
Translators, when adding/updating your translation files, please follow
the following rules:
* Do not update debian/changelog:
- The file will get generated out of the commit messages at release time.
- Beware that you should NOT update any of the legacy ChangeLog.old
files for translation updates.
* Format of commit message
Following guidelines in <https://wiki.debian.org/Teams/Dpkg/GitUsage>
you should start the commit message with a summary line, followed by an
empty line and optional pseudo-headers.
The summary line should use the following format:
«po: <Action> <Language> [<part> ]translation»
Where:
- <Action> is one of “Update” or “Add”,
- <Language> should be capitalized (such as “English”),
- <part> should be one of «programs» (for lib/, src/ and utils/), «dselect»,
«scripts» and «man pages» (man/), or not be set if the commit includes
changes to various parts.
For example:
==========================================================
po: Update German programs translation
Closes: #123456
Reviewed-by: Full Name <email@example.org>
==========================================================
* Use of po/LINGUAS, dselect/po/LINGUAS or scripts/po/LINGUAS:
When ADDING a new translation, don't forget adding the language to
the LINGUAS file, otherwise it will not be used.
* Always CHECK your translations:
You MUST check your PO files for validity.
The correct syntax for doing so is:
$ msgmerge --update <file> dpkg.pot
$ msgfmt --check --output-file /dev/null --statistics <file>
$ msgcat <file> >/dev/null
- msgmerge updates your file with the current POT file.
- msgfmt checks it for validity.
- msgcat may detect encoding problems.
In addition to the above, the easiest way to check that the po4a
translations have valid POD markup, is to try to build them (please
see the Building sections in the README file for further details
regarding the setup of the source tree):
$ make -C man

243
THANKS Normal file
View file

@ -0,0 +1,243 @@
A Costa <agcosta@gis.net>
Aaron M. Ucko <ucko@debian.org>
Adam Conrad <adconrad@0c3.net>
Adam Heath <doogie@debian.org>
Adeodato Simó <adeodato@debian.org>
Alberto Garcia <berto@gpul.org>
Américo Monteiro <a_monteiro@gmx.com>
Anand Kumria <wildfire@progsoc.org>
Andreas Barth <aba@not.so.argh.org>
Andreas Metzler <ametzler@debian.org>
Andreas Påhlsson <andreas.pahlsson@xcerion.com>
Andrew Ferrier <andrew@new-destiny.co.uk>
Andrew Hobson <ahobson@eng.mindspring.net>
Andrew Suffield <asuffield@debian.org>
Anthony Towns <aj@azure.humbug.org.au>
Aurelien Jarno <aurel32@debian.org>
Bart Cornelis <cobaco@skolelinux.no>
Bart Martens <bart.martens@advalvas.be>
Bastian Kleineidam <calvin@debian.org>
Bastien ROUCARIÈS <roucaries.bastien@gmail.com>
Ben Collins <bcollins@debian.org>
Ben Hutchings <ben@decadent.org.uk>
Ben Pfaff <blp@cs.stanford.edu>
Bill Allombert <ballombe@debian.org>
Bjarni Ingi Gislason <bjarniig@rhi.hi.is>
Boyuan Yang <byang@debian.org>
Branden Robinson <branden@debian.org>
Branko Lankester
Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
Bruce Perens <bruce@pixar.com>
Bruce Sass <bmsass@shaw.ca>
Carl Streeter <streeter@cae.wisc.edu>
Carlos Laviola <claviola@brfree.com.br>
Carlos Z.F. Liu <carlosliu@users.sourceforge.net>
Carsten Hey <carsten@debian.org>
Carsten Leonhardt <leo@debian.org>
Changwoo Ryu <cwryu@debian.org>
Charles Briscoe-Smith <cpbs@debian.org>
Chris Lamb <lamby@debian.org>
Christian Haggstrom <chm@c00.info>
Christoph Biedl <debian.axhn@manchmal.in-ulm.de>
Christoph Maser <cm@financial.com>
Christophe Le Bars <clebars@teaser.fr>
Claus Hindsgaul <claus.hindsgaul@gmail.com>
Clytie Siddall <clytie@riverland.net.au>
Colin Plumb <colin@nyx.net>
Colin Watson <cjwatson@debian.org>
Dafydd Harries <daf@muse.19inch.net>
Dan Gohman <gohmandj@mrs.umn.edu>
Dan Streetman <ddstreet@canonical.com>
Daniel Hahler <debian-bugs@thequod.de>
Daniel Jacobowitz <dan@debian.org>
Daniel Kahn Gillmor <dkg@fifthhorseman.net>
Daniel Leidert <daniel.leidert@wgdd.de>
Daniel Nylander <yeager@lidkoping.net>
Daniel Shahaf <danielsh@apache.org>
Darren Stalder <torin@daft.com>
David Huggins-Daines <dhd@debian.org>
David Kalnischkies <david@kalnischkies.de>
David Lopez Moreno <david.lopez.moreno@hispalinux.es>
David Rabel <david.rabel@noresoft.com>
Denis Barbier <barbier@debian.org>
Didier Vidal <didier-devel@melix.net>
Dmitry Shachnev <mitya57@debian.org>
Don Armstrong <don@debian.org>
Eddy Petrișor <eddy.petrisor@gmail.com>
Erast Benson <erast@gnusolaris.org>
Erick Branderhorst <branderhorst@heel.fgg.eur.nl>
Flavio Stanchina <flavio@stanchina.net>
Frank S. Thomas <frank@thomas-alfeld.de>
Frans Spiesschaert <Frans.Spiesschaert@yucom.be>
Frédéric Bothamy <frederic.bothamy@free.fr>
Galen Hazelwood <galenh@debian.org>
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
Guy Maor <maor@debian.org>
Hanno Böck <hanno@hboeck.de>
Hans Fredrik Nordhaug <hans@nordhaug.priv.no>
Hartmut Koptein <koptein@naffel.de>
Heiko Schlittermann <hs@schlittermann.de>
Helge Kreutzmann <debian@helgefjell.de>
Helmut Grohne <helmut@subdivi.de>
Hiroshi KISE <fuyuneko@ryukyu.ne.jp>
Holger Wansing <linux@wansing-online.de>
Ian Eure <ieure@debian.org>
Ian Jackson <ijackson@chiark.greenend.org.uk>
Ian Murdock <imurdock@debian.org>
Ian Zimmerman <itz@buug.org>
Ingo Saitz <ingo@debian.org>
Ivar Smolin <okul@linux.ee>
Ivo Timmermans <itimmermans@bigfoot.com>
J.H.M. Dassen <jdassen@cistron.nl>
Jack Bates <wdz7eo@nottheoilrig.com>
Jacobo Tarrio <jtarrio@debian.org>
Jakub Wilk <jwilk@debian.org>
James R. Van Zandt <jrvz@comcast.net>
James Troup <troup@debian.org>
James Vega <jamessan@debian.org>
Jared Spiegel <jrrs@frontiernet.net>
Jari Aalto <jari.aalto@cante.net>
Javier Fernández-Sanguino Peña <jfs@debian.org>
Javier Serrano Polo <javier@jasp.net>
Jean-Pierre Giraud <jenapierregiraud75@free.fr>
Jeffrey W. Baker <jwbaker@acm.org>
Jeroen van Wolffelaar <jeroen@wolffelaar.nl>
Jessica Clarke <jrtc27@debian.org>
Jim Pick <jim@jimpick.com>
Jim Van Zandt <jrv@vanzandt.mv.com>
Jiří Paleček <jpalecek@web.de>
Joachim Breitner <mail@joachim-breitner.de>
Joel Klecker <jk@espy.org>
Joey Hess <joeyh@debian.org>
Johannes Schauer <josch@debian.org>
Johannes Veser <veser@gmx.de>
John Wright <jsw@debian.org>
John Zaitseff <J.Zaitseff@zap.org.au>
Jonathan Nieder <jrnieder@gmail.com>
Jordi Mallach <jordi@debian.org>
Josh Soref <jsoref@gmail.com>
Josh Triplett <josh@joshtriplett.org>
Josip Rodin <jrodin@jagor.srce.hr>
Juan Cespedes <cespedes@debian.org>
Juergen Menden <menden@morgana.camelot.de>
Juho Vuori <javuori@cc.helsinki.fi>
Julian Andres Klode <jak@debian.org>
Julian Gilbey <jdg@debian.org>
Julian R <debian@styxxx.de>
Julien Cristau <jcristau@debian.org>
Junichi Uekawa <dancer@debian.org>
Justin Pryzby <justinpryzby@users.sourceforge.net>
Jörg Sonnenberger <joerg@netbsd.org>
Ken Bloom <kbloom@gmail.com>
Kenshi Muto <kmuto@debian.org>
Kevin Ryde <user42@zip.com.au>
Kim-Minh Kaplan <kkaplan@cdfhp3.in2p3.fr>
Klee Dienes <klee@debian.org>
Koblinger Egmont <egmont@uhulinux.hu>
Kurt B. Kaiser <kbk@shore.net>
Kylan Robinson <Kylan_Robinson@selinc.com>
Lele Gaifax <lele@seldati.it>
Lennert Buytenhek <buytenh+debian@wantstofly.org>
Ludovic Rousseau <rousseau@debian.org>
Manoj Srivastava <srivasta@debian.org>
Manuel A. Fernandez Montecelo <mafm@debian.org>
Marc Dequènes <duck@duckcorp.org>
Marc Haber <mh+debian-packages@zugschlus.de>
Marcel Toele <mtoele@kern.nl>
Marcin Owsiany <marcin@owsiany.pl>
Marco d'Itri <md@linux.it>
Marcus Brinkmann <brinkmd@debian.org>
Marek Vasut <marex@denx.de>
Mark Rosenstand <mark@borkware.net>
Martin Bagge <martin.bagge@glesys.se>
Martin Koeppe <mkoeppe@gmx.de>
Martin Pitt <martin.pitt@ubuntu.com>
Masato Taruishi <taru@debian.or.jp>
Mathias Weidner <mathias@weidner.in-bad-schmiedeberg.de>
Matt Kraai <kraai@ftbfs.org>
Matt Welsh <mdw@sunsite.unc.edu>
Matt Zimmerman <mdz@debian.org>
Mattia Rizzolo <mattia@debian.org>
Maximilian Attems <debian@sternwelten.at>
Mert Dirik <mertdirik@gmail.com>
Michael Alan Dorman <mdorman@calder.med.miami.edu>
Michael Shields <shields@crosslink.net>
Michael Sobolev <mss@transas.com>
Michael Vogt <mvo@ubuntu.com>
Michel Lespinasse <walken@zoy.org>
Miguel Figueiredo <elmig@debianpt.org>
Miguel Figueiredo <elmig@debianpt.org>
Milo Casagrande <milo@milo.name>
Miquel van Smoorenburg <miquels@cistron.nl>
Miroslav Kure <kurem@debian.cz>
Mo Zhou <lumin@debian.org>
Modestas Vainius <modax@debian.org>
Moritz Muehlenhoff <jmm@inutil.org>
NIIBE Yutaka <gniibe@fsij.org>
Niall Walsh <niallwalsh@celtux.org>
Nicolas Bonifas
Nicolas Boulenguez <nicolas@debian.org>
Nicolas François <nicolas.francois@centraliens.net>
Nicolás Lichtmaier <nick@debian.org>
Niels Thykier <niels@thykier.net>
Nils Rennebarth <nils@debian.org>
Nishanth Aravamudan <nish.aravamudan@canonical.com>
Ondřej Surý <ondrej@sury.org>
Paul Wise <pabs@debian.org>
Peter Krefting <peter@softwolves.pp.se>
Peter Mann <Peter.Mann@tuke.sk>
Peter van Dijk <peter@dataloss.nl>
Petr Cech <cech@atrey.karlin.mff.cuni.cz>
Philippe Batailler <pbatailler@teaser.fr>
Pierre Habouzit <madcoder@debian.org>
Pietro Battiston <me@pietrobattiston.it>
Piotr Engelking <inkerman42@gmail.com>
Piotr Roszatycki <dexter@fnet.pl>
Quentin PAGÈS <quentinantonin@free.fr>
Rakesh 'arky' Ambati <rakesh_ambati@yahoo.com>
Ralf Treinen <treinen@free.fr>
Raphaël Hertzog <hertzog@debian.org>
Reiner Herrmann <reiner@reiner-h.de>
Richard Kettlewell <rjk@sfere.greenend.org.uk>
Riku Voipio <riku.voipio@iki.fi>
Robert Luberda <robert@debian.org>
Robert Millan <rmh@debian.org>
Roderich Schupp <roderich.schupp@gmail.com>
Roderick Schertler <roderick@argon.org>
Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Russell Coker <russell@coker.com.au>
SZERVÁC Attila <sas@321.hu>
Samuel Thibault <samuel.thibault@ens-lyon.org>
Scott Barker <scott@mostlylinux.ab.ca>
Scott James Remnant <scott@netsplit.com>
Sean Finney <seanius@seanius.net>
Sergio Gelato <Sergio.Gelato@astro.su.se>
Stefano Canepa <sc@linux.it>
Stepan Golosunov <stepan@golosunov.pp.ru>
Stephane Bortzmeyer <stephane@sources.org>
Steve Langasek <vorlon@debian.org>
Steven Chamberlain <steven@pyro.eu.org>
Sven Joachim <svenjoac@gmx.de>
Sven Rudolph <sr1@loom.sax.de>
Takuma Yamada <tyamada@takumayamada.com>
Taowa Munene-Tardif <taowa@debian.org>
Thomas Klausner <wiz@NetBSD.org>
Thomas Morin <thomas.morin@enst-bretagne.fr>
Timothy G Abbott <tabbott@MIT.EDU>
Tom Goulet <tomg@sentex.ca>
Tom Lees <tom@lpsg.demon.co.uk>
Tomas Pospisek <tpo_deb@sourcepole.ch>
Topi Miettinen <Topi.Miettinen@nic.fi>
Trek <trek00@inbox.ru>
Trần Ngọc Quân <vnwildman@gmail.com>
Vagrant Cascadian <vagrant@reproducible-builds.org>
Vasilis Vasaitis <v.vasaitis@sms.ed.ac.uk>
Wayne Davison <wayned@users.sourceforge.net>
Wichert Akkerman <wakkerma@debian.org>
YunQiang Su <wzssyqa@gmail.com>
Yuri Gribov <tetra2005@gmail.com>
Yuri Kozlov <kozlov.y@gmail.com>
Zefram <zefram@fysh.org>
Zhou Mo <cdluminate@gmail.com>
Łukasz Dulny <bartekchom@poczta.onet.pl>
林博仁(Buo-ren Lin) <Buo.Ren.Lin@gmail.com>

151
TODO Normal file
View file

@ -0,0 +1,151 @@
RoadMap
=======
<https://wiki.debian.org/Teams/Dpkg/RoadMap>
TODO
====
Recurring
---------
* Review this file and remove or update the old entries.
* Look for FIXME and XXX items in the source.
* Triage as much bugs as possible to get the bug count below 300 ;)
and merge as much patches as possible.
Projects
--------
* Merge functionality from debsigs-verify, debsigs:
- Redesign OpenPGP signatures support within .deb archive and its policy.
* Add UTF-8 support to all programs.
* Discuss and implement:
<https://www.hadrons.org/~guillem/debian/docs/origin.proposal>.
Tasks
-----
* C/C++ code cleanup / bug fixes:
- Get rid of static variables inside functions.
- Coalesce hash and checksum functions.
- Split modstatdb_rw into mode and flags.
- Move fd function out of mustlib.
- Cleanup status chars -> strings hardcoded mappings all over the place.
(Fix tied field enum with its dselect description (pkgdisplay.cc))
- Refactor src/unpack.c.
- Split dpkg.h into independent headers.
- Do more unused header include removal.
- Add needed includes to all header files.
- Get rid of useless "unsigned" modifiers.
- Use enums for currently hardcoded literals (replacingfilesandsaid,
filetriggers_edited, etc).
- Do not use nfmalloc (and friends) for non in-core db memory.
- Call nffreeall on exit (need to detangle nfmalloc from non-db first).
- Add a size parameter to the buffer API to avoid some useless
pipe+fork+copy.
- Handle instdir '/' separator consistently.
- Check if caching selinux context for second call is possible.
- Add missing newlines in --version output.
- Handle symlinks in statcmd.c statdb_node_apply().
- Fix dpkg termination on SIGPIPE from status-fd.
* libcompat cleanup:
- Add fnmatch, IRIX5 doesn't have it.
* Man pages:
- Add example to dpkg-scanfoo manual pages?
- Merge synopsis lines in dpkg-triggers.
- Check all command vs action.
- Check usage of '|' instead of ', '.
- Check position of short option before long option.
- Fix dpkg man page, refs to dpkg-deb and dpkg-split, etc.
- Fix «. ».
* L10n:
- Check dpkg-divert strings for new and fixable ones.
- Standardize translated error messages in the perl code to avoid useless
work for translators.
* s-s-d: Add POSIX capabilities support.
* dpkg: Deprecate --force-not-root (remove modstatdb_rw rootneeded flags).
* dpkg: Test and re-enable --command-fd.
* dpkg: Check --no-act for log_action().
* test: Add non-regression tests for Dpkg::Source::*.
* dpkg: Allow packages to register additional files, declare ownership of
files for dpkg -S and -L without having dpkg act on this (.psuedolist?).
* dpkg-checkbuilddeps: Make it easier to use by other programs such as
pbuilder or sbuild, so that they can start using the new architecture
wildcards automatically.
- Support for output format. (#214566)
* libdpkg: Fix conflicting action -%c, when short is 0.
* libdpkg: We should set our own obstack_alloc_failed_handler.
* dpkg: Declarative diversions, as a control archive entry.
* dpkg: --status for virtual packages.
? dpkg: --query, -Q.
* dpkg: Filename field generated by --record-avail.
? dpkg: Allow external program to specify how to handle conffiles.
? dpkg: Add --call-maint-script=<script> --maint-script-arg=<arg>
--maint-script-arg=<arg> <pkg> <pkg>
Where dpkg would not allow <script> to be one of {pre,post}{inst,rm}.
Only unknown scripts can be called this way. dpkg would also not keep
track of any state for these scripts.
? dpkg: _Always_ show section in --yet-to-unpack.
* dpkg: Fix:
<joeyh_> package a conflicted with old versions of package b. package b
conflicted with old versions of package a. I had the old versions
of both installed, and told dpkg to install the new versions of
a and b simultaneously. It refused.
* dselect: Automatically do --yet-to-unpack in installation methods.
* dselect: Make it understand Replaces.
* dselect: Per-half focus and keybindings improvements.
!missing bug report #1555!
Inadequacies (ponder, some might be fine)
------------
* Conflicts << installation ordering.
* Search for all pre-depends things at once, bomb out if any not found.
* Check depending packages when installing new version.
* Several things ought to be configurable but are not.
* Filenames containing newlines.
* Conffile names containing spaces.
* Handling of case in package names.
* 'fake' or 'null' packages (useful for equivs or fink system packages).
* Local conffiles, as well as local files that dpkg should check before
overwriting.

1740
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load diff

9
autogen Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
set -e
if [ -e .git ] && command -v git >/dev/null 2>&1; then
git config blame.ignoreRevsFile .git-blame-ignore-revs
fi
autoreconf --force --install

279
build-aux/ar-lib Executable file
View file

@ -0,0 +1,279 @@
#! /bin/sh
# Wrapper for Microsoft lib.exe
me=ar-lib
scriptversion=2024-06-19.01; # UTC
# Copyright (C) 2010-2024 Free Software Foundation, Inc.
# Written by Peter Rosin <peda@lysator.liu.se>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# func_error message
func_error ()
{
echo "$me: $1" 1>&2
exit 1
}
file_conv=
# func_file_conv build_file
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv in
mingw)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin | msys)
file=`cygpath -m "$file" || echo "$file"`
;;
wine)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_at_file at_file operation archive
# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
# for each of them.
# When interpreting the content of the @FILE, do NOT use func_file_conv,
# since the user would need to supply preconverted file names to
# binutils ar, at least for MinGW.
func_at_file ()
{
operation=$2
archive=$3
at_file_contents=`cat "$1"`
eval set x "$at_file_contents"
shift
for member
do
$AR -NOLOGO $operation:"$member" "$archive" || exit $?
done
}
case $1 in
'')
func_error "no command. Try '$0 --help' for more information."
;;
-h | --h*)
cat <<EOF
Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
Members may be specified in a file named with @FILE.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
EOF
exit $?
;;
-v | --v*)
echo "$me (GNU Automake) $scriptversion"
exit $?
;;
esac
if test $# -lt 3; then
func_error "you must specify a program, an action and an archive"
fi
AR=$1
shift
while :
do
if test $# -lt 2; then
func_error "you must specify a program, an action and an archive"
fi
case $1 in
-lib | -LIB \
| -ltcg | -LTCG \
| -machine* | -MACHINE* \
| -subsystem* | -SUBSYSTEM* \
| -verbose | -VERBOSE \
| -wx* | -WX* )
AR="$AR $1"
shift
;;
-nologo | -NOLOGO)
# We always invoke AR with -nologo, so don't need to add it again.
shift
;;
*)
action=$1
shift
break
;;
esac
done
orig_archive=$1
shift
func_file_conv "$orig_archive"
archive=$file
# strip leading dash in $action
action=${action#-}
delete=
extract=
list=
quick=
replace=
index=
create=
while test -n "$action"
do
case $action in
d*) delete=yes ;;
x*) extract=yes ;;
t*) list=yes ;;
q*) quick=yes ;;
r*) replace=yes ;;
s*) index=yes ;;
S*) ;; # the index is always updated implicitly
c*) create=yes ;;
u*) ;; # TODO: don't ignore the update modifier
v*) ;; # TODO: don't ignore the verbose modifier
*)
func_error "unknown action specified"
;;
esac
action=${action#?}
done
case $delete$extract$list$quick$replace,$index in
yes,* | ,yes)
;;
yesyes*)
func_error "more than one action specified"
;;
*)
func_error "no action specified"
;;
esac
if test -n "$delete"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
for member
do
case $1 in
@*)
func_at_file "${1#@}" -REMOVE "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
;;
esac
done
elif test -n "$extract"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
if test $# -gt 0; then
for member
do
case $1 in
@*)
func_at_file "${1#@}" -EXTRACT "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
;;
esac
done
else
$AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \
| while read member
do
$AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
done
fi
elif test -n "$quick$replace"; then
if test ! -f "$orig_archive"; then
if test -z "$create"; then
echo "$me: creating $orig_archive"
fi
orig_archive=
else
orig_archive=$archive
fi
for member
do
case $1 in
@*)
func_file_conv "${1#@}"
set x "$@" "@$file"
;;
*)
func_file_conv "$1"
set x "$@" "$file"
;;
esac
shift
shift
done
if test -n "$orig_archive"; then
$AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
else
$AR -NOLOGO -OUT:"$archive" "$@" || exit $?
fi
elif test -n "$list"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
$AR -NOLOGO -LIST "$archive" || exit $?
fi

40
build-aux/autotest.am Normal file
View file

@ -0,0 +1,40 @@
EXTRA_DIST += $(srcdir)/at/package.m4
DISTCLEANFILES += at/atconfig
AUTOTEST_DEPS = at/atconfig at/atlocal $(TESTSUITE)
TEST_VERBOSE ?= 0
TEST_PARALLEL ?= 1
TEST_VERBOSE_OPT = $(TEST_VERBOSE:0=)
TESTSUITEFLAGS =
TESTSUITEFLAGS += -j$(TEST_PARALLEL)
TESTSUITEFLAGS += $(TEST_VERBOSE_OPT:1=--verbose)
# The ":;" works around a Bash 3.2 bug when the output is not writable.
$(srcdir)/at/package.m4: $(top_srcdir)/configure.ac
:;{ \
echo '# Signature of the current package.' && \
echo 'm4_define([AT_PACKAGE_NAME], [$(PACKAGE_NAME)])' && \
echo 'm4_define([AT_PACKAGE_TARNAME], [$(PACKAGE_TARNAME)])' && \
echo 'm4_define([AT_PACKAGE_VERSION], [$(PACKAGE_VERSION)])' && \
echo 'm4_define([AT_PACKAGE_STRING], [$(PACKAGE_STRING)])' && \
echo 'm4_define([AT_PACKAGE_URL], [$(PACKAGE_URL)])' && \
echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])'; \
} >'$(srcdir)/at/package.m4'
autotest-check: $(AUTOTEST_DEPS)
$(SHELL) '$(TESTSUITE)' -C at $(TESTSUITEFLAGS)
autotest-installcheck: $(AUTOTEST_DEPS)
$(SHELL) '$(TESTSUITE)' -C at AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
autotest-clean:
test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' -C at --clean
AUTOTEST = $(AUTOM4TE) --language=autotest
$(TESTSUITE): $(srcdir)/at/package.m4 $(TESTSUITE_AT)
$(AUTOTEST) -I '$(srcdir)/at' -o $@.tmp $@.at
mv $@.tmp $@

351
build-aux/compile Executable file
View file

@ -0,0 +1,351 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2024-06-19.01; # UTC
# Copyright (C) 1999-2024 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/* | msys/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.lo | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
EOF
exit $?
;;
-v | --v*)
echo "compile (GNU Automake) $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

1815
build-aux/config.guess vendored Executable file

File diff suppressed because it is too large Load diff

751
build-aux/config.rpath Executable file
View file

@ -0,0 +1,751 @@
#! /bin/sh
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in a binary (executable or
# shared library).
#
# Copyright 1996-2024 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# Known limitations:
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
# than 256 bytes, otherwise the compiler driver will dump core. The only
# known workaround is to choose shorter directory names for the build
# directory and/or the installation directory.
# func_usage
# outputs to stdout the --help usage message.
func_usage ()
{
echo "\
Usage: config.rpath [OPTION] HOST
Prints shell variable assignments that describe how to hardcode a directory
for the lookup of shared libraries into a binary (executable or shared library).
The first argument passed to this file is the canonical host specification,
CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
or
CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
should be set by the caller.
The set of defined variables is at the end of this script.
Options:
--help print this help and exit
--version print version information and exit
Send patches and bug reports to <bug-gnulib@gnu.org>."
}
# func_version
# outputs to stdout the --version message.
func_version ()
{
echo "config.rpath (GNU gnulib, module havelib)"
echo "Copyright (C) 2024 Free Software Foundation, Inc.
License: All-Permissive.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
echo
printf 'Written by %s.\n' "Bruno Haible"
}
# func_fatal_error message
# outputs to stderr a fatal error message, and terminates the program.
func_fatal_error ()
{
echo "config.rpath: *** $1" 1>&2
echo "config.rpath: *** Stop." 1>&2
exit 1
}
# Command-line option processing.
while test $# -gt 0; do
case "$1" in
--help | --hel | --he | --h )
func_usage
exit 0 ;;
--version | --versio | --versi | --vers | --ver | --ve | --v )
func_version
exit 0 ;;
-- ) # Stop option processing
shift; break ;;
-* )
func_fatal_error "unrecognized option: $1"
;;
* )
break ;;
esac
done
if test $# -gt 1; then
func_fatal_error "too many arguments"
fi
if test $# -lt 1; then
func_fatal_error "too few arguments"
fi
# All known linkers require a '.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
shrext=.so
host="$1"
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
# Code taken from libtool.m4's _LT_CC_BASENAME.
for cc_temp in $CC""; do
case $cc_temp in
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
# Code taken from libtool.m4's _LT_COMPILER_PIC.
wl=
if test "$GCC" = yes; then
wl='-Wl,'
else
case "$host_os" in
aix*)
wl='-Wl,'
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
;;
hpux9* | hpux10* | hpux11*)
wl='-Wl,'
;;
irix5* | irix6* | nonstopux*)
wl='-Wl,'
;;
linux* | k*bsd*-gnu | kopensolaris*-gnu)
case $cc_basename in
ecc*)
wl='-Wl,'
;;
icc* | ifort*)
wl='-Wl,'
;;
lf95*)
wl='-Wl,'
;;
nagfor*)
wl='-Wl,-Wl,,'
;;
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
wl='-Wl,'
;;
ccc*)
wl='-Wl,'
;;
xl* | bgxl* | bgf* | mpixl*)
wl='-Wl,'
;;
como)
wl='-lopt='
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ F* | *Sun*Fortran*)
wl=
;;
*Sun\ C*)
wl='-Wl,'
;;
esac
;;
esac
;;
newsos6)
;;
*nto* | *qnx*)
;;
osf3* | osf4* | osf5*)
wl='-Wl,'
;;
rdos*)
;;
solaris*)
case $cc_basename in
f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
wl='-Qoption ld '
;;
*)
wl='-Wl,'
;;
esac
;;
sunos4*)
wl='-Qoption ld '
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
wl='-Wl,'
;;
sysv4*MP*)
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
wl='-Wl,'
;;
unicos*)
wl='-Wl,'
;;
uts4*)
;;
esac
fi
# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
hardcode_libdir_flag_spec=
hardcode_libdir_separator=
hardcode_direct=no
hardcode_minus_L=no
case "$host_os" in
cygwin* | mingw* | pw32* | cegcc*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
esac
ld_shlibs=yes
if test "$with_gnu_ld" = yes; then
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
# Unlike libtool, we use -rpath here, not --rpath, since the documented
# option of GNU ld is called -rpath, not --rpath.
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
case "$host_os" in
aix[3-9]*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
ld_shlibs=no
fi
;;
amigaos*)
case "$host_cpu" in
powerpc)
;;
m68k)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
esac
;;
beos*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
cygwin* | mingw* | pw32* | cegcc*)
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
haiku*)
;;
interix[3-9]*)
hardcode_direct=no
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
netbsd*)
;;
solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
ld_shlibs=no
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
else
ld_shlibs=no
fi
;;
esac
;;
sunos4*)
hardcode_direct=yes
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
esac
if test "$ld_shlibs" = no; then
hardcode_libdir_flag_spec=
fi
else
case "$host_os" in
aix3*)
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
if test "$GCC" = yes; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
fi
;;
aix[4-9]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
fi
hardcode_direct=yes
hardcode_libdir_separator=':'
if test "$GCC" = yes; then
case $host_os in aix4.[012]|aix4.[012].*)
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" && \
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
hardcode_direct=unsupported
hardcode_minus_L=yes
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
;;
esac
fi
# Begin _LT_AC_SYS_LIBPATH_AIX.
echo 'int main () { return 0; }' > conftest.c
${CC} ${LDFLAGS} conftest.c -o conftest
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
fi
if test -z "$aix_libpath"; then
aix_libpath="/usr/lib:/lib"
fi
rm -f conftest.c conftest
# End _LT_AC_SYS_LIBPATH_AIX.
if test "$aix_use_runtimelinking" = yes; then
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
else
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
fi
fi
;;
amigaos*)
case "$host_cpu" in
powerpc)
;;
m68k)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
esac
;;
bsdi[45]*)
;;
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec=' '
libext=lib
;;
darwin* | rhapsody*)
hardcode_direct=no
if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then
:
else
ld_shlibs=no
fi
;;
dgux*)
hardcode_libdir_flag_spec='-L$libdir'
;;
freebsd2.[01]*)
hardcode_direct=yes
hardcode_minus_L=yes
;;
freebsd* | dragonfly* | midnightbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
hpux9*)
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
hpux10*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
fi
;;
hpux11*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
case $host_cpu in
hppa*64*|ia64*)
hardcode_direct=no
;;
*)
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
netbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
newsos6)
hardcode_direct=yes
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
*nto* | *qnx*)
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
else
case "$host_os" in
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
hardcode_libdir_flag_spec='-R$libdir'
;;
*)
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
esac
fi
else
ld_shlibs=no
fi
;;
os2*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
osf3*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*)
if test "$GCC" = yes; then
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
else
# Both cc and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
fi
hardcode_libdir_separator=:
;;
solaris*)
hardcode_libdir_flag_spec='-R$libdir'
;;
sunos4*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=yes
hardcode_minus_L=yes
;;
sysv4)
case $host_vendor in
sni)
hardcode_direct=yes # is this really true???
;;
siemens)
hardcode_direct=no
;;
motorola)
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
;;
esac
;;
sysv4.3*)
;;
sysv4*MP*)
if test -d /usr/nec; then
ld_shlibs=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
;;
sysv5* | sco3.2v5* | sco5v6*)
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
hardcode_libdir_separator=':'
;;
uts4*)
hardcode_libdir_flag_spec='-L$libdir'
;;
*)
ld_shlibs=no
;;
esac
fi
# Check dynamic linker characteristics
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
# only about the one the linker finds when passed -lNAME. This is the last
# element of library_names_spec in libtool.m4, or possibly two of them if the
# linker has special search rules.
library_names_spec= # the last element of library_names_spec in libtool.m4
libname_spec='lib$name'
case "$host_os" in
aix3*)
library_names_spec='$libname.a'
;;
aix[4-9]*)
library_names_spec='$libname$shrext'
;;
amigaos*)
case "$host_cpu" in
powerpc*)
library_names_spec='$libname$shrext' ;;
m68k)
library_names_spec='$libname.a' ;;
esac
;;
beos*)
library_names_spec='$libname$shrext'
;;
bsdi[45]*)
library_names_spec='$libname$shrext'
;;
cygwin* | mingw* | pw32* | cegcc*)
shrext=.dll
library_names_spec='$libname.dll.a $libname.lib'
;;
darwin* | rhapsody*)
shrext=.dylib
library_names_spec='$libname$shrext'
;;
dgux*)
library_names_spec='$libname$shrext'
;;
freebsd[23].*)
library_names_spec='$libname$shrext$versuffix'
;;
freebsd* | dragonfly* | midnightbsd*)
library_names_spec='$libname$shrext'
;;
gnu*)
library_names_spec='$libname$shrext'
;;
haiku*)
library_names_spec='$libname$shrext'
;;
hpux9* | hpux10* | hpux11*)
case $host_cpu in
ia64*)
shrext=.so
;;
hppa*64*)
shrext=.sl
;;
*)
shrext=.sl
;;
esac
library_names_spec='$libname$shrext'
;;
interix[3-9]*)
library_names_spec='$libname$shrext'
;;
irix5* | irix6* | nonstopux*)
library_names_spec='$libname$shrext'
case "$host_os" in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
*) libsuff= shlibsuff= ;;
esac
;;
esac
;;
linux*oldld* | linux*aout* | linux*coff*)
;;
linux* | k*bsd*-gnu | kopensolaris*-gnu)
library_names_spec='$libname$shrext'
;;
knetbsd*-gnu)
library_names_spec='$libname$shrext'
;;
netbsd*)
library_names_spec='$libname$shrext'
;;
newsos6)
library_names_spec='$libname$shrext'
;;
*nto* | *qnx*)
library_names_spec='$libname$shrext'
;;
openbsd*)
library_names_spec='$libname$shrext$versuffix'
;;
os2*)
libname_spec='$name'
shrext=.dll
library_names_spec='$libname.a'
;;
osf3* | osf4* | osf5*)
library_names_spec='$libname$shrext'
;;
rdos*)
;;
solaris*)
library_names_spec='$libname$shrext'
;;
sunos4*)
library_names_spec='$libname$shrext$versuffix'
;;
sysv4 | sysv4.3*)
library_names_spec='$libname$shrext'
;;
sysv4*MP*)
library_names_spec='$libname$shrext'
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
library_names_spec='$libname$shrext'
;;
tpf*)
library_names_spec='$libname$shrext'
;;
uts4*)
library_names_spec='$libname$shrext'
;;
esac
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
# How to pass a linker flag through the compiler.
wl="$escaped_wl"
# Static library suffix (normally "a").
libext="$libext"
# Shared library suffix (normally "so").
shlibext="$shlibext"
# Format of library name prefix.
libname_spec="$escaped_libname_spec"
# Library names that the linker finds when passed -lNAME.
library_names_spec="$escaped_library_names_spec"
# Flag to hardcode \$libdir into a binary during linking.
# This must work even if \$libdir does not exist.
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
# Whether we need a single -rpath flag with a separated argument.
hardcode_libdir_separator="$hardcode_libdir_separator"
# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
# resulting binary.
hardcode_direct="$hardcode_direct"
# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
# resulting binary.
hardcode_minus_L="$hardcode_minus_L"
EOF

2354
build-aux/config.sub vendored Executable file

File diff suppressed because it is too large Load diff

46
build-aux/cpan.am Normal file
View file

@ -0,0 +1,46 @@
CPAN_DIST_NAME = $(PACKAGE_CPAN_NAME)
CPAN_DIST_VERSION = $(PACKAGE_VERSION)
if !PACKAGE_DIST_IS_RELEASE
CPAN_DIST_SUFFIX = -TRIAL
endif
CPAN_DIST = $(CPAN_DIST_NAME)-$(CPAN_DIST_VERSION)$(CPAN_DIST_SUFFIX)
CPAN_DIST_ARCHIVE = $(CPAN_DIST).tar.gz
dist-cpan:
: # Create the CPAN source tree.
mkdir -p $(CPAN_DIST)
mkdir -p $(CPAN_DIST)/lib
mkdir -p $(CPAN_DIST)/t
cp -fpR $(top_srcdir)/COPYING $(CPAN_DIST)/LICENSE
cp -fpR $(top_srcdir)/debian/changelog $(CPAN_DIST)/Changes
cp -fpR $(top_srcdir)/data $(CPAN_DIST)
cp -fpR $(top_srcdir)/t/* \
$(top_srcdir)/scripts/t/Dpkg* \
$(top_srcdir)/scripts/t/origins \
$(CPAN_DIST)/t
cp -fpR $(top_srcdir)/scripts/Dpkg.pm $(CPAN_DIST)/lib/
cp -fpR $(top_srcdir)/scripts/Dpkg $(CPAN_DIST)/lib/
cp -fpR $(top_srcdir)/scripts/Test $(CPAN_DIST)/lib/
cp -fpR $(top_builddir)/scripts/README.cpan $(CPAN_DIST)/README
cp -fpR $(top_builddir)/scripts/Build.PL $(CPAN_DIST)
: # Fix permissions of the distributed files.
find $(CPAN_DIST) \
-type d ! -perm 755 -exec chmod u+rwx,go+rx {} ';' -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; || \
chmod -R a+r $(CPAN_DIST)
: # Prepare the CPAN distribution.
cd $(CPAN_DIST) && $(PERL) Build.PL
cd $(CPAN_DIST) && ./Build manifest
cd $(CPAN_DIST) && ./Build distdir
: # Pack the CPAN distribution.
$(TAR) -caf $(CPAN_DIST_ARCHIVE) -C $(CPAN_DIST) -Hustar \
--sort=name --owner=root:0 --group=root:0 $(CPAN_DIST)
: # Cleanup the CPAN source tree.
find $(CPAN_DIST) -type d ! -perm -200 -exec chmod u+w {} ';'
rm -rf $(CPAN_DIST)

792
build-aux/depcomp Executable file
View file

@ -0,0 +1,792 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2024-06-19.01; # UTC
# Copyright (C) 1999-2024 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp (GNU Automake) $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interference from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsolete pre-3.x GCC compilers.
## but also to in-use compilers like IBM xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

303
build-aux/gen-changelog Executable file
View file

@ -0,0 +1,303 @@
#!/usr/bin/perl
#
# gen-changelog
#
# Copyright © 2020-2022 Guillem Jover <guillem@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
use strict;
use warnings;
use lib qw(scripts);
use List::Util qw(uniq);
use Text::Wrap;
use Dpkg::IPC;
use Dpkg::Index;
my @sections = qw(
main
arch
port
perl-mod
make-mod
shell-mod
doc
code-int
build-sys
pkg
test
l10n
);
my %sections = (
arch => {
title => 'Architecture support',
match => qr/^arch: /,
},
port => {
title => 'Portability',
type => 'porting',
},
'perl-mod' => {
title => 'Perl modules',
match => qr/^(?:Test|Dpkg|Dselect).*[,:] /,
keep => 1,
},
'make-mod' => {
title => 'Make fragments',
match => qr{^scripts/mk: },
},
'shell-mod' => {
title => 'Shell library',
match => qr{^src/sh: },
},
doc => {
title => 'Documentation',
match => qr/^(?:doc|man)[,:] /,
keep => 1,
},
'code-int' => {
title => 'Code internals',
type => 'internal',
match => qr/^(?:lib(?:compat|dpkg)?|src|scripts|perl|utils): /,
keep => 1,
},
'build-sys' => {
title => 'Build system',
match => qr/^build: /,
},
pkg => {
title => 'Packaging',
match => qr/^debian: /,
},
test => {
title => 'Test suite',
match => qr/^(?:test|t): /,
},
l10n => {
title => 'Localization',
match => qr/^po: /,
sort => 1,
},
);
my @metafields = qw(
Thanks-to
Co-Author
Based-on-patch-by
Improved-by
Prompted-by
Reported-by
Required-by
Analysis-by
Requested-by
Suggested-by
Spotted-by
Naming-by
Ref
);
my %metafield = (
'Co-Author' => 'Co-authored by',
'Based-on-patch-by' => 'Based on a patch by',
'Improved-by' => 'Improved by',
'Prompted-by' => 'Prompted by',
'Reported-by' => 'Reported by',
'Required-by' => 'Required by',
'Analysis-by' => 'Analysis by',
'Requested-by' => 'Requested by',
'Suggested-by' => 'Suggested by',
'Spotted-by' => 'Spotted by',
'Naming-by' => 'Naming by',
'Thanks-to' => 'Thanks to',
'Ref' => 'See',
);
my %mappings = (
'u-a' => 'update-alternatives',
's-s-d' => 'start-stop-daemon',
'dpkg-m-h' => 'dpkg-maintscript-helper',
);
my $log_format =
'Commit: %H%n' .
'Author: %aN%n' .
'AuthorEmail: %aE%n' .
'Committer: %cN%n' .
'CommitterEmail: %cE%n' .
'Title: %s%n' .
'%(trailers:only,unfold)%N';
my $tag_prev = $ARGV[0];
my $tag_next = $ARGV[1] // "";
$tag_prev //= qx(git describe --abbrev=0);
chomp $tag_prev;
my $fh_gitlog;
spawn(
exec => [
qw(git log --first-parent), "--format=tformat:$log_format",
"$tag_prev..$tag_next"
],
to_pipe => \$fh_gitlog,
);
my $log = Dpkg::Index->new(
get_key_func => sub { return $_[0]->{Commit} },
item_opts => {
keep_duplicate => 1,
allow_duplicate => 1,
},
);
$log->parse($fh_gitlog, 'git log');
my %entries;
my %groups;
my @groups;
# Analyze the commits and select which group and section to place them in.
foreach my $id (reverse $log->get_keys()) {
my $commit = $log->get_by_key($id);
my $title = $commit->{Title};
my $group = $commit->{Committer};
my $changelog = $commit->{'Changelog'};
my $sectmatch = 'main';
# Skip irrelevant commits.
if ($title =~ m/^(?:Bump version to|Release) /) {
next;
}
if ($title =~ m/^po: Regenerate/) {
next;
}
if (defined $changelog) {
# Skip silent commits.
next if $changelog =~ m/(?:silent|skip|ignore)/;
# Include the entire commit body for verbose commits.
if ($changelog =~ m/(?:verbose|full)/) {
my $body = qx(git show -s --pretty=tformat:%b $id);
$commit->{Title} .= "\n$body";
}
if ($changelog =~ m{s/([^/]+)/([^/]+)/}) {
$commit->{Fixup} = {
old => $1,
new => $2,
};
}
}
# Decide into what section the commit should go.
foreach my $sectname (keys %sections) {
my $section = $sections{$sectname};
if ((exists $section->{match} and $title =~ m/$section->{match}/) or
(exists $section->{type} and defined $changelog and
$changelog =~ m/$section->{type}/)) {
$sectmatch = $sectname;
last;
}
}
# Add the group entries in order, with l10n ones at the end.
if (not exists $entries{$group}) {
push @groups, $group;
}
push @{$entries{$group}{$sectmatch}}, $commit;
}
# Go over the groups and their sections and format them.
foreach my $groupname (@groups) {
print "\n";
print " [ $groupname ]\n";
foreach my $sectname (@sections) {
my $section = $sections{$sectname};
next unless exists $entries{$groupname}{$sectname};
next if @{$entries{$groupname}{$sectname}} == 0;
if (exists $sections{$sectname}->{title}) {
print " * $sections{$sectname}->{title}:\n";
}
my @entries;
foreach my $commit (@{$entries{$groupname}{$sectname}}) {
my $title = $commit->{Title} =~ s/\.$//r . '.';
# Remove the title prefix if needed.
if (exists $section->{match} and not exists $section->{keep}) {
$title =~ s/$section->{match}//;
}
# Metafields.
if ($commit->{Author} ne $commit->{Committer}) {
$commit->{'Thanks-to'} = "$commit->{Author} <$commit->{AuthorEmail}>";
}
foreach my $metafield (@metafields) {
next unless exists $commit->{$metafield};
my $values = $commit->{$metafield};
$values = [ $values ] if ref $values ne 'ARRAY';
foreach my $value (@{$values}) {
$title .= "\n$metafield{$metafield} $value.";
}
}
# Handle the Closes metafield last.
if (exists $commit->{Closes}) {
$title .= " Closes: $commit->{Closes}";
}
# Handle fixups from git notes.
if (exists $commit->{Fixup}) {
$title =~ s/\Q$commit->{Fixup}{old}\E/$commit->{Fixup}{new}/m;
}
# Handle mappings.
foreach my $mapping (keys %mappings) {
$title =~ s/$mapping/$mappings{$mapping}/g;
}
# Select prefix formatting.
my ($entry_tab, $body_tab);
if (not exists $sections{$sectname}->{title}) {
$entry_tab = ' * ';
$body_tab = ' ';
} else {
$entry_tab = ' - ';
$body_tab = ' ';
}
local $Text::Wrap::columns = 80;
local $Text::Wrap::unexpand = 0;
local $Text::Wrap::huge = 'overflow';
local $Text::Wrap::break = qr/(?<!Closes:)\s/;
push @entries, wrap($entry_tab, $body_tab, $title) . "\n";
}
if ($sections{$sectname}->{sort}) {
@entries = uniq(sort @entries);
}
print @entries;
}
}

166
build-aux/gen-release Executable file
View file

@ -0,0 +1,166 @@
#!/bin/sh
#
# gen-release
#
# Copyright © 2017-2024 Guillem Jover <guillem@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
set -x
set -e
set -u
# Pre-checks.
# Currently requires packages: dpkg-dev, git, schroot and devscripts
# (the latter should eventually be replaced by dpkg tools).
for req in dpkg-parsechangelog git schroot dch debsign dscverify; do
if ! command -v $req >/dev/null 2>&1; then
echo "error: missing required command $req" >&2
exit 1
fi
done
if [ "$(dpkg-parsechangelog -SSource)" != 'dpkg' ] || ! [ -e .git ]; then
echo "error: not inside the dpkg git tree" >&2
exit 1
fi
# Setup.
dist="${1:-unstable}"
relver="${2:-$(dpkg-parsechangelog -SVersion)}"
numjobs="$(nproc)"
checkflags="-j$numjobs AUTHOR_TESTING=1 TEST_PARALLEL=$numjobs"
dircode="$(pwd)"
dirtests="$dircode/tests"
dirbuild="$(mktemp --tmpdir --directory release-dpkg.XXXXXXXX)"
# Update the source chroot.
schroot -c "source:$dist" -- sudo eatmydata apt-get --yes update
schroot -c "source:$dist" -- sudo eatmydata apt-get --yes upgrade
# Setup a clean chroot session.
chroot="$(schroot -c "$dist" -b)"
echo "Release start: $(date -Iseconds)"
cd "$dircode"
schroot -c "$chroot" -r -- sudo eatmydata apt-get --yes build-dep \
-P pkg.dpkg.author-testing,pkg.dpkg.author-release .
if ! git log --format=tformat:%s -s HEAD~2.. | grep 'po: Regenerate'; then
# Clean slate.
git clean -Xdf
# Update the .pot and .po files.
echo "$relver" >.dist-version
schroot -c "$chroot" -r -- ./autogen
schroot -c "$chroot" -r -- ./configure
schroot -c "$chroot" -r -- make update-po
rm -f .dist-version
git commit -a -m 'po: Regenerate .pot files and merge .po files with them'
fi
if [ -z "$(git tag --list "$relver")" ]; then
# Finalize the actual release.
genchangelog='build-aux/gen-changelog'
sed -i -e "2e$genchangelog" -e '2,3d' debian/changelog
dch -r -D"$dist"
git commit -a -m "Release $relver"
git tag -s "$relver" -m "Release $relver"
elif [ "$(git describe)" != "$relver" ]; then
echo "error: mismatched tag for $relver not on git HEAD" >&2
exit 1
fi
# Clean slate.
git clean -Xdf
# Prepare the tarball for distribution.
schroot -c "$chroot" -r -- ./autogen
schroot -c "$chroot" -r -- ./configure
if [ "$dist" = unstable ]; then
# Generate the CPAN distribution only from main.
make dist-cpan
fi
# shellcheck disable=SC2086
schroot -c "$chroot" -r -- make $checkflags distcheck
# Prepare for packaged release.
mkdir -p "$dirbuild"
cp "dpkg-$relver.tar.xz" "$dirbuild/"
# Teardown pre-release chroot.
schroot -c "$chroot" -e
cd "$dirbuild"
# Setup a clean chroot session for the dist tarballs.
chroot="$(schroot -c "$dist" -b)"
# Build twice, to make sure we can build ourselves with the new dpkg,
# and to verify that we are building reproducibly.
# Build A and B in a chroot.
for iter in a b; do (
mkdir -p "build-$iter"
cd "build-$iter"
tar xaf "../dpkg-$relver.tar.xz"
cd "dpkg-$relver"
schroot -c "$chroot" -r -- sudo eatmydata apt-get --yes build-dep .
schroot -c "$chroot" -r -- dpkg-buildpackage -us -uc --changes-option=-S
# Install resulting .debs.
schroot -c "$chroot" -r -- sudo eatmydata dpkg -iO ../*.deb
) done
# Run functional test-suite.
(
set -x
set -e
set -u
cd "$dirtests"
schroot -c "$chroot" -r -- sudo eatmydata apt-get --yes purge pkg-config
schroot -c "$chroot" -r -- eatmydata make test-clean clean
schroot -c "$chroot" -r -- eatmydata make test 2>&1 | tee test.log
)
schroot -c "$chroot" -r -- sudo eatmydata apt-get --yes install lintian
# Verify the result.
diff -u build-a/dpkg_*.changes build-b/dpkg_*.changes || true
# Prompt to continue? (.buildinfo will differ)
diff -u build-a/dpkg_*.buildinfo build-b/dpkg_*.buildinfo || true
# Prompt to continue? (Build-Date, Environment will differ).
schroot -c "$chroot" -r -- lintian build-b/*.changes build-b/*.deb
# Teardown chroot.
schroot -c "$chroot" -e
# Sign and verify.
cd "$dirbuild/build-b"
debsign dpkg_"${relver}"_*.changes
dscverify dpkg_"${relver}"_*.changes
ls -l "$(pwd)"
echo "Release process finished (dpkg ${relver}): $(date -Iseconds)"
echo " Hint: upload to CPAN"
echo " Hint: update https://www.wikidata.org/wiki/Q305892"

49
build-aux/get-vcs-id Executable file
View file

@ -0,0 +1,49 @@
#!/bin/sh
#
# get-vcs-id
#
# Copyright © 2009-2024 Guillem Jover <guillem@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
error()
{
echo "get-vcs-id: error: $*" 1>&2
exit 1
}
if [ -f .dist-vcs-id ]; then
# Get the VCS id from the file distributed in the tarball.
id="$(cat .dist-vcs-id)"
elif [ -d .git ] || [ -f .git ]; then
if ! command -v git >/dev/null; then
error "cannot get project VCS id, git checkout but git program not found"
fi
# Get the VCS id from the git repository.
id="$(git rev-list -1 HEAD 2>/dev/null)"
# Check if we are on a dirty checkout.
git update-index --refresh -q >/dev/null
dirty=$(git diff-index --name-only HEAD 2>/dev/null)
if [ -n "$dirty" ]; then
id="$id-dirty"
fi
else
error "cannot get project VCS id, not a git checkout nor a distribution tarball."
fi
# Use printf to avoid the trailing new line that m4_esyscmd would not handle.
printf "%s" "$id"

50
build-aux/get-version Executable file
View file

@ -0,0 +1,50 @@
#!/bin/sh
#
# get-version
#
# Copyright © 2009, 2013-2015, 2018, 2020 Guillem Jover <guillem@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
error()
{
echo "get-version: error: $*" 1>&2
exit 1
}
if [ -f .dist-version ]; then
# Get the version from the file distributed in the tarball.
version=$(cat .dist-version)
elif [ -d .git ] || [ -f .git ]; then
if ! command -v git >/dev/null; then
error "cannot get project version, git checkout but git program not found"
fi
# Get the version from the git repository. Since tags cannot contain colons
# or tildes, we use percent and underscore instead. Reverse that switch here.
version=$(git describe --abbrev=4 HEAD 2>/dev/null | tr %_ :~)
# Check if we are on a dirty checkout.
git update-index --refresh -q >/dev/null
dirty=$(git diff-index --name-only HEAD 2>/dev/null)
if [ -n "$dirty" ]; then
version="$version-dirty"
fi
else
error "cannot get project version, not a git checkout nor a distribution tarball."
fi
# Use printf to avoid the trailing new line that m4_esyscmd would not handle.
printf "%s" "$version"

541
build-aux/install-sh Executable file
View file

@ -0,0 +1,541 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2024-06-19.01; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-p pass -p to $cpprog.
-s $stripprog installed files.
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
By default, rm is invoked with -f; when overridden with RMPROG,
it's up to you to specify -f if you want it.
If -S is not specified, no backups are attempted.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>."
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-p) cpprog="$cpprog -p";;
-s) stripcmd=$stripprog;;
-S) backupsuffix="$2"
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 (GNU Automake) $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibility with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# If $backupsuffix is set, and the file being installed
# already exists, attempt a backup. Don't worry if it fails,
# e.g., if mv doesn't support -f.
if test -n "$backupsuffix" && test -f "$dst"; then
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
fi
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

98
build-aux/lcov-inject Executable file
View file

@ -0,0 +1,98 @@
#!/usr/bin/perl
#
# lcov-inject
#
# Copyright © 2014-2024 Guillem Jover <guillem@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
use strict;
use warnings;
use Cwd;
use Devel::Cover::DB;
my $dir = 'scripts';
my $cwd = getcwd();
chdir $dir or die "cannot switch to $dir\n";
my $db = Devel::Cover::DB->new(db => 'cover_db');
$db = $db->merge_runs();
$db->calculate_summary(map { $_ => 1 } $db->collected());
chdir $cwd or die "cannot switch to $cwd\n";
my $s = $db->{summary}{Total};
my $tmpl = sprintf '
<td class="coverDirectory"><a href="%s">%s</a></td>
<td class="coverBar" align="center">
<table border=0 cellspacing=0 cellpadding=1>
<tr><td class="coverBarOutline">%s</td></tr>
</table>
</td>
%s
%s
%s
</tr>
<tr>
', "$dir/coverage.html", $dir, bar_html($s->{total}{percentage}),
box_html($s->{total}), box_html($s->{branch}), box_html($s->{subroutine});
while (<>) {
s/^(.*<td .*href="utils\/index\.html".*<\/td>.*)$/$tmpl$1/;
print;
}
sub bar_image {
my ($num) = @_;
return 'emerald.png' if $num >= 90;
return 'ruby.png' if $num < 75;
return 'amber.png';
}
sub bar_html {
my ($num) = @_;
my $html = sprintf '<img src="%s" width=%.0f height=10 alt="%.1f">',
bar_image($num), $num, $num;
if ($num < 100) {
$html .= sprintf '<img src="snow.png" width=%.0f height=10 alt="%.1f">',
100 - $num, $num;
}
return $html;
}
sub box_rating {
my ($num) = @_;
return 'Hi' if $num >= 90;
return 'Lo' if $num < 75;
return 'Med';
}
sub box_html {
my ($stats) = @_;
return sprintf '<td class="coverPer%s">%.1f&nbsp;%%</td>' . "\n" .
'<td class="coverNum%s">%d</td>' . "\n" .
'<td class="coverNum%s">%d</td>',
box_rating($stats->{percentage}), $stats->{percentage},
'Dflt', $stats->{total}, 'Dflt', $stats->{covered};
}

11523
build-aux/ltmain.sh Executable file

File diff suppressed because it is too large Load diff

236
build-aux/missing Executable file
View file

@ -0,0 +1,236 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU and other programs.
scriptversion=2024-06-07.14; # UTC
# shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autogen autoheader autom4te automake autoreconf
bison flex help2man lex makeinfo perl yacc
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing (GNU Automake) $scriptversion"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=https://www.perl.org/
flex_URL=https://github.com/westes/flex
gnu_software_URL=https://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake|autoreconf)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
*)
:
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
autoheader_deps="'acconfig.h'"
automake_deps="'Makefile.am'"
aclocal_deps="'acinclude.m4'"
case $normalized_program in
aclocal*)
echo "You should only need it if you modified $aclocal_deps or"
echo "$configure_deps."
;;
autoconf*)
echo "You should only need it if you modified $configure_deps."
;;
autogen*)
echo "You should only need it if you modified a '.def' or '.tpl' file."
echo "You may want to install the GNU AutoGen package:"
echo "<$gnu_software_URL/autogen/>"
;;
autoheader*)
echo "You should only need it if you modified $autoheader_deps or"
echo "$configure_deps."
;;
automake*)
echo "You should only need it if you modified $automake_deps or"
echo "$configure_deps."
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
;;
autoreconf*)
echo "You should only need it if you modified $aclocal_deps or"
echo "$automake_deps or $autoheader_deps or $automake_deps or"
echo "$configure_deps."
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
perl*)
echo "You should only need it to run GNU Autoconf, GNU Automake, "
echo " assorted other tools, or if you modified a Perl source file."
echo "You may want to install the Perl 5 language interpreter:"
echo "<$perl_URL>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
program_details "$normalized_program"
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

21
build-aux/run-script Executable file
View file

@ -0,0 +1,21 @@
#!/bin/sh
set -e
top_srcdir="$(dirname "$0")/.."
# To avoid using «readlink -f» or «realpath» we just change into the
# desired directory and work from there.
cd "$top_srcdir"
cwd="$(pwd)"
cd "$OLDPWD"
# Set up the environment, to use local perl modules and data files.
export PERL="${PERL:-perl}"
export PERL5LIB="$cwd/scripts:$cwd/dselect/methods"
export DPKG_DATADIR="$cwd/data"
script="$1"
shift 1
exec "$PERL" "$cwd/$script" "$@"

48
build-aux/subst.am Normal file
View file

@ -0,0 +1,48 @@
#
# Build time variable substitution for generated files.
#
# Shell support.
subst_shell_rules = "\
s{^ADMINDIR=.*$$}{ADMINDIR='$(admindir)'}; \
s{^BACKUPSDIR=.*$$}{BACKUPSDIR='$(backupsdir)'}; \
s{^PKGDATADIR_DEFAULT=.*$$}{PKGDATADIR_DEFAULT='$(pkgdatadir)'}; \
s{^version=['\"][^'\"]*[\"']}{version=\"$(PACKAGE_VERSION)\"}; \
s{^TAR=.*$$}{TAR='$(TAR)'}; \
"
subst_shell_filter = $(PERL) -p -e $(subst_shell_rules)
subst_shell_file = $(PERL) -i -p -e $(shell_subst_rules)
SUFFIXES += .sh
.sh: Makefile
@test -d `dirname $@` || $(MKDIR_P) `dirname $@`
$(AM_V_GEN) $(subst_shell_filter) <$< >$@
$(AM_V_at) chmod +x $@
# Perl support.
# Note: We need to hex-escape '#' (0x23) to avoid portability issues with make.
subst_perl_rules = "\
s{^\x23!\s*/usr/bin/perl}{\x23!$(PERL)}; \
s{our \\\$$CONFDIR = .*;}{our \\\$$CONFDIR = '$(pkgconfdir)';}; \
s{our \\\$$ADMINDIR = .*;}{our \\\$$ADMINDIR = '$(admindir)';}; \
s{our \\\$$LIBDIR = .*;}{our \\\$$LIBDIR = '$(pkglibexecdir)';}; \
s{our \\\$$DATADIR = .*;}{our \\\$$DATADIR = '$(pkgdatadir)';}; \
s{our \\\$$PROGMAKE = .*;}{our \\\$$PROGMAKE = '$(MAKE)';}; \
s{our \\\$$PROGTAR = .*;}{our \\\$$PROGTAR = '$(TAR)';}; \
s{our \\\$$PROGPATCH = .*;}{our \\\$$PROGPATCH = '$(PATCH)';}; \
s{our \\\$$PROGVERSION = .*;}{our \\\$$PROGVERSION = '$(PACKAGE_VERSION)';}; \
"
subst_perl_filter = $(PERL) -p -e $(subst_perl_rules)
subst_perl_file = $(PERL) -i -p -e $(subst_perl_rules)
SUFFIXES += .pl
.pl: Makefile
@test -d `dirname $@` || $(MKDIR_P) `dirname $@`
$(AM_V_GEN) $(subst_perl_filter) <$< >$@
$(AM_V_at) chmod +x $@

38
build-aux/tap.am Normal file
View file

@ -0,0 +1,38 @@
# Variables to be defined:
#
# TEST_VERBOSE - set to 0 (default) or 1 to control test suite verbosity
# TEST_PARALLEL - set to 1 (default) or N to control the parallel jobs
# TEST_ENV_VARS - environment variables to be set for the test suite
# TEST_COVERAGE - set to the perl module in charge of getting test coverage
# test_tmpdir - test suite temporary directory
# test_scripts - list of test case scripts
# test_programs - list of test case programs
# test_data - list of test data files
TEST_VERBOSE ?= 0
TEST_PARALLEL ?= 1
tap-clean:
[ -z "$(test_tmpdir)" ] || rm -fr $(test_tmpdir)
tap-check: $(test_data) $(test_programs) $(test_scripts)
[ -z "$(test_tmpdir)" ] || $(MKDIR_P) $(test_tmpdir)
$(TEST_ENV_VARS) \
TEST_PARALLEL=$(TEST_PARALLEL) \
TEST_VERBOSE=$(TEST_VERBOSE) \
abs_srcdir=$(abs_srcdir) \
abs_builddir=$(abs_builddir) \
abs_top_srcdir=$(abs_top_srcdir) \
abs_top_builddir=$(abs_top_builddir) \
srcdir=$(srcdir) builddir=$(builddir) \
CC=$(CC) \
SHELL=$(SHELL) \
PERL=$(PERL) \
PERL_DL_NONLAZY=1 \
PERL5OPT=$(TEST_COVERAGE) \
$(PERL) $(top_srcdir)/build-aux/test-runner \
$(addprefix $(builddir)/,$(test_programs)) \
$(addprefix $(srcdir)/,$(test_scripts))
authorcheck:
AUTHOR_TESTING=1 $(MAKE) check

42
build-aux/test-runner Executable file
View file

@ -0,0 +1,42 @@
#!/usr/bin/perl
use strict;
use warnings;
use TAP::Harness;
my $srcroot = $ENV{abs_top_srcdir};
my $binroot = $ENV{abs_top_builddir};
# Setup the environment
$ENV{LC_ALL} = 'C';
$ENV{DPKG_COLORS} = 'never';
$ENV{PATH} = "$binroot/src:$binroot/scripts:$binroot/utils:$ENV{PATH}";
my %options;
# XXX: We need force the file formatter to workaround verbose + parallel
# not working correctly, as the console formatter eats the test output,
# see <https://github.com/Perl-Toolchain-Gang/Test-Harness/issues/105>.
if ($ENV{TEST_VERBOSE} && $ENV{TEST_PARALLEL} > 1) {
$options{formatter_class} = 'TAP::Formatter::File';
}
my $harness = TAP::Harness->new({
exec => sub {
my (undef, $test) = @_;
return [ $test ] if $test !~ m/\.t$/ and -x $test;
return
},
lib => [
"$srcroot/scripts",
"$srcroot/dselect/methods"
],
color => 1,
verbosity => $ENV{TEST_VERBOSE},
jobs => $ENV{TEST_PARALLEL},
failures => 1,
%options,
});
my $aggregate = $harness->runtests(@ARGV);
die "FAIL: test suite has errors\n" if $aggregate->has_errors;

580
config.h.in Normal file
View file

@ -0,0 +1,580 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* The normal alignment of 'max_align_t', in bytes. */
#undef ALIGNOF_MAX_ALIGN_T
/* Set this to the canonical dpkg architecture name. */
#undef ARCHITECTURE
/* Set this to the canonical dpkg CPU name. */
#undef ARCHITECTURE_CPU
/* Set this to the canonical dpkg system name. */
#undef ARCHITECTURE_OS
/* Define to 1 if dselect is compiled. */
#undef BUILD_DSELECT
/* Define to 1 if start-stop-daemon is compiled. */
#undef BUILD_START_STOP_DAEMON
/* Define to 1 if update-alternatives is compiled. */
#undef BUILD_UPDATE_ALTERNATIVES
/* default dpkg-deb build compressor */
#undef DEB_DEFAULT_COMPRESSOR
/* pager program used by dpkg */
#undef DPKG_DEFAULT_PAGER
/* POSIX shell interpreter used by dpkg */
#undef DPKG_DEFAULT_SHELL
/* Whether structured procfs supports LFS */
#undef DPKG_STRUCTURED_PROCFS_SUPPORTS_LFS
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
/* Define to 1 if you have the 'alphasort' function. */
#undef HAVE_ALPHASORT
/* Define to 1 if you have the 'asprintf' function. */
#undef HAVE_ASPRINTF
/* Define to 1 if the 'snprintf' family is C99 conformant */
#undef HAVE_C99_SNPRINTF
/* Define to 1 if you have the Mac OS X function
CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */
#undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES
/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
the CoreFoundation framework. */
#undef HAVE_CFPREFERENCESCOPYAPPVALUE
/* Define to 1 if you have the 'closefrom' function. */
#undef HAVE_CLOSEFROM
/* Define to 1 if you have the 'close_range' function. */
#undef HAVE_CLOSE_RANGE
/* Define to 1 if you have the <curses.h> header file. */
#undef HAVE_CURSES_H
/* Define to 1 if you have the <cxxabi.h> header file. */
#undef HAVE_CXXABI_H
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
#undef HAVE_DCGETTEXT
/* Define to 1 if you have the declaration of 'sys_errlist', and to 0 if you
don't. */
#undef HAVE_DECL_SYS_ERRLIST
/* Define to 1 if you have the declaration of 'sys_nerr', and to 0 if you
don't. */
#undef HAVE_DECL_SYS_NERR
/* Define to 1 if you have the declaration of 'sys_siglist', and to 0 if you
don't. */
#undef HAVE_DECL_SYS_SIGLIST
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* POSIX shell interpreter used by dpkg supports -- after -c */
#undef HAVE_DPKG_SHELL_WITH_DASH_DASH
/* Define to 1 if you have the <error.h> header file. */
#undef HAVE_ERROR_H
/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H
/* Define to 1 if you have the 'fallocate' function. */
#undef HAVE_FALLOCATE
/* Define to 1 if you have the 'fgetgrent' function. */
#undef HAVE_FGETGRENT
/* Define to 1 if you have the 'fgetpwent' function. */
#undef HAVE_FGETPWENT
/* Define to 1 if the 'fsync' function works on directories */
#undef HAVE_FSYNC_DIR
/* Define to 1 if 'F_ALLOCSP64' is declared in <fcntl.h> */
#undef HAVE_F_ALLOCSP64
/* Define to 1 if 'F_PREALLOCATE' is declared in <fcntl.h> */
#undef HAVE_F_PREALLOCATE
/* Define to 1 if you have the 'getdtablesize' function. */
#undef HAVE_GETDTABLESIZE
/* Define to 1 if you have the 'getexecname' function. */
#undef HAVE_GETEXECNAME
/* Define to 1 if you have the 'getopt' function. */
#undef HAVE_GETOPT
/* Define to 1 if you have the 'getopt_long' function. */
#undef HAVE_GETOPT_LONG
/* Define to 1 if you have the 'getprocs64' function. */
#undef HAVE_GETPROCS64
/* Define to 1 if you have the 'getprogname' function. */
#undef HAVE_GETPROGNAME
/* Define if the GNU gettext() function is already present or preinstalled. */
#undef HAVE_GETTEXT
/* Define if you have the iconv() function and it works. */
#undef HAVE_ICONV
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <kvm.h> header file. */
#undef HAVE_KVM_H
/* Define to 1 if you have the 'lchown' function. */
#undef HAVE_LCHOWN
/* Define to 1 if you have the <libintl.h> header file. */
#undef HAVE_LIBINTL_H
/* Define to 1 if you have the <linux/fiemap.h> header file. */
#undef HAVE_LINUX_FIEMAP_H
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the 'lutimes' function. */
#undef HAVE_LUTIMES
/* xz multi-threaded decompression support */
#undef HAVE_LZMA_MT_DECODER
/* xz multi-threaded compression support */
#undef HAVE_LZMA_MT_ENCODER
/* Define to 1 if 'makedev' is declared in <sys/types.h> */
#undef HAVE_MAKEDEV
/* Define to 1 if you have the <md5.h> header file. */
#undef HAVE_MD5_H
/* Define to 1 if you have the <minix/config.h> header file. */
#undef HAVE_MINIX_CONFIG_H
/* Define to 1 if you have the 'mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
#undef HAVE_NCURSESW_NCURSES_H
/* Define to 1 if you have the <ncursesw/term.h> header file. */
#undef HAVE_NCURSESW_TERM_H
/* Define to 1 if you have the <ncurses.h> header file. */
#undef HAVE_NCURSES_H
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
#undef HAVE_NCURSES_NCURSES_H
/* Define to 1 if you have the <ncurses/term.h> header file. */
#undef HAVE_NCURSES_TERM_H
/* Define to 1 if you have the 'obstack_free' function. */
#undef HAVE_OBSTACK_FREE
/* Define to 1 if 'offsetof' is declared in <stddef.h> */
#undef HAVE_OFFSETOF
/* Define to 1 if 'O_NOFOLLOW' is declared in <fcntl.h> */
#undef HAVE_O_NOFOLLOW
/* Define to 1 if you have the 'posix_fadvise' function. */
#undef HAVE_POSIX_FADVISE
/* Define to 1 if you have the 'posix_fallocate' function. */
#undef HAVE_POSIX_FALLOCATE
/* Define to 1 if you have program_invocation_short_name */
#undef HAVE_PROGRAM_INVOCATION_SHORT_NAME
/* Define to 1 if 'P_tmpdir' is declared in <stdio.h> */
#undef HAVE_P_TMPDIR
/* Define to 1 if you have the 'scandir' function. */
#undef HAVE_SCANDIR
/* Define to 1 if you have the 'setsid' function. */
#undef HAVE_SETSID
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the 'strchrnul' function. */
#undef HAVE_STRCHRNUL
/* Define to 1 if you have the 'strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the 'strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if you have the 'strnlen' function. */
#undef HAVE_STRNLEN
/* Define to 1 if you have the 'strsignal' function. */
#undef HAVE_STRSIGNAL
/* Define to 1 if the system has the type 'struct psinfo'. */
#undef HAVE_STRUCT_PSINFO
/* Define to 1 if you have the <sys/mkdev.h> header file. */
#undef HAVE_SYS_MKDEV_H
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/procfs.h> header file. */
#undef HAVE_SYS_PROCFS_H
/* Define to 1 if you have the <sys/proc.h> header file. */
#undef HAVE_SYS_PROC_H
/* Define to 1 if you have the <sys/pstat.h> header file. */
#undef HAVE_SYS_PSTAT_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#undef HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#undef HAVE_SYS_SYSCTL_H
/* Define to 1 if you have the <sys/sysmacros.h> header file. */
#undef HAVE_SYS_SYSMACROS_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/user.h> header file. */
#undef HAVE_SYS_USER_H
/* Define to 1 if you have the <term.h> header file. */
#undef HAVE_TERM_H
/* Define to 1 if 'TIOCNOTTY' is declared in <sys/ioctl.h> */
#undef HAVE_TIOCNOTTY
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the 'unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the 'uselocale' function. */
#undef HAVE_USELOCALE
/* Define to 1 if the 'va_copy' macro exists */
#undef HAVE_VA_COPY
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H
/* Define to 1 if 'WCOREDUMP' is declared in <sys/wait.h> */
#undef HAVE_WCOREDUMP
/* Define to 1 if you have the <xlocale.h> header file. */
#undef HAVE_XLOCALE_H
/* Define to 1 if you have the '__cxa_pure_virtual' function. */
#undef HAVE___CXA_PURE_VIRTUAL
/* Define to 1 if you have __progname */
#undef HAVE___PROGNAME
/* Acknowledge the volatility of the API. */
#undef LIBDPKG_VOLATILE_API
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define the project release information, version and architecture */
#undef PACKAGE_RELEASE
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* GNU patch program */
#undef PATCH
/* The size of 'double', as computed by sizeof. */
#undef SIZEOF_DOUBLE
/* The size of 'float', as computed by sizeof. */
#undef SIZEOF_FLOAT
/* The size of 'int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of 'long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of 'long double', as computed by sizeof. */
#undef SIZEOF_LONG_DOUBLE
/* The size of 'long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of 'off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* The size of 'short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of 'time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* The size of 'void *', as computed by sizeof. */
#undef SIZEOF_VOID_P
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* GNU tar program */
#undef TAR
/* Use disk size pre-allocation */
#undef USE_DISK_PREALLOCATE
/* Define to the zlib implementation to use */
#undef USE_LIBZ_IMPL
/* Define none as 0 for the zlib implementation enum */
#undef USE_LIBZ_IMPL_NONE
/* Define zlib as 1 for the zlib implementation enum */
#undef USE_LIBZ_IMPL_ZLIB
/* Define zlib-ng as 2 for the zlib implementation enum */
#undef USE_LIBZ_IMPL_ZLIB_NG
/* Use unreliable mmap support */
#undef USE_MMAP
/* Enable extensions on AIX, Interix, z/OS. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable general extensions on macOS. */
#ifndef _DARWIN_C_SOURCE
# undef _DARWIN_C_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable X/Open compliant socket functions that do not require linking
with -lxnet on HP-UX 11.11. */
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
# undef _HPUX_ALT_XOPEN_SOCKET_API
#endif
/* Identify the host operating system as Minix.
This macro does not affect the system headers' behavior.
A future release of Autoconf may stop defining this macro. */
#ifndef _MINIX
# undef _MINIX
#endif
/* Enable general extensions on NetBSD.
Enable NetBSD compatibility extensions on Minix. */
#ifndef _NETBSD_SOURCE
# undef _NETBSD_SOURCE
#endif
/* Enable OpenBSD compatibility extensions on NetBSD.
Oddly enough, this does nothing on OpenBSD. */
#ifndef _OPENBSD_SOURCE
# undef _OPENBSD_SOURCE
#endif
/* Define to 1 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_SOURCE
# undef _POSIX_SOURCE
#endif
/* Define to 2 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_1_SOURCE
# undef _POSIX_1_SOURCE
#endif
/* Enable POSIX-compatible threading on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
# undef __STDC_WANT_IEC_60559_BFP_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# undef __STDC_WANT_IEC_60559_DFP_EXT__
#endif
/* Enable extensions specified by C23 Annex F. */
#ifndef __STDC_WANT_IEC_60559_EXT__
# undef __STDC_WANT_IEC_60559_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
#endif
/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
#ifndef __STDC_WANT_LIB_EXT2__
# undef __STDC_WANT_LIB_EXT2__
#endif
/* Enable extensions specified by ISO/IEC 24747:2009. */
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
# undef __STDC_WANT_MATH_SPEC_FUNCS__
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable X/Open extensions. Define to 500 only if necessary
to make mbstate_t available. */
#ifndef _XOPEN_SOURCE
# undef _XOPEN_SOURCE
#endif
/* Version number of package */
#undef VERSION
/* Define to yes to use zlib-ng gzFile IO support */
#undef WITH_GZFILEOP
/* Define to 1 to use bz2 library rather than console tool */
#undef WITH_LIBBZ2
/* Define to 1 to use lzma library rather than console tool */
#undef WITH_LIBLZMA
/* Define to 1 to compile in SELinux support */
#undef WITH_LIBSELINUX
/* Define to 1 to use z library rather than console tool */
#undef WITH_LIBZ
/* Define to 1 to use zstd library rather than console tool */
#undef WITH_LIBZSTD
/* Define to 1 to use z-ng library rather than console tool */
#undef WITH_LIBZ_NG
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to 1 on platforms where this makes off_t a 64-bit type. */
#undef _LARGE_FILES
/* Number of bits in time_t, on hosts where this is settable. */
#undef _TIME_BITS
/* Define to 1 if type 'char' is unsigned and your compiler does not
predefine this macro. */
#ifndef __CHAR_UNSIGNED__
# undef __CHAR_UNSIGNED__
#endif
/* Define to 1 on platforms where this makes time_t a 64-bit type. */
#undef __MINGW_USE_VC2005_COMPAT
/* Define to empty if 'const' does not conform to ANSI C. */
#undef const
/* Define to '__inline__' or '__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to 'int' if <sys/types.h> does not define. */
#undef mode_t
/* Define as a signed integer type capable of holding a process identifier. */
#undef pid_t
/* Define to 'int' if <malloc.h> does not define. */
#undef ptrdiff_t
/* Define as 'unsigned int' if <stddef.h> doesn't define. */
#undef size_t
/* Define to empty if the keyword 'volatile' does not work. Warning: valid
code using 'volatile' can become incorrect without. Disable with care. */
#undef volatile

40146
configure vendored Executable file

File diff suppressed because it is too large Load diff

352
configure.ac Normal file
View file

@ -0,0 +1,352 @@
# Process this file with autoconf to produce a configure script.
m4_pattern_forbid([^_?DPKG_])
AC_PREREQ(2.60)
AC_INIT([dpkg], m4_esyscmd([build-aux/get-version]),
[debian-dpkg@lists.debian.org], [dpkg],
[https://wiki.debian.org/Teams/Dpkg])
DPKG_DIST_IS_RELEASE
AC_SUBST([PACKAGE_COPYRIGHT_HOLDER], ['Dpkg Developers'])
AC_SUBST([PACKAGE_VCS_ID], m4_esyscmd([build-aux/get-vcs-id]))
AC_SUBST([PACKAGE_VCS_TYPE], [git])
AC_SUBST([PACKAGE_VCS_URL], [https://git.dpkg.org/git/dpkg/dpkg.git])
AC_SUBST([PACKAGE_VCS_WEB], [https://git.dpkg.org/cgit/dpkg/dpkg.git])
AC_SUBST([PACKAGE_BUG_WEB], [https://bugs.debian.org/src:dpkg])
AC_SUBST([PACKAGE_CPAN_NAME], [Dpkg])
AC_CONFIG_SRCDIR([lib/dpkg/dpkg.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE(
[1.11]
[-Wall]
[foreign]
[nostdinc]
[subdir-objects]
[tar-ustar no-dist-gzip dist-xz]
)
AM_SILENT_RULES([yes])
# Require at least this gettext version, but will take any later version too.
AM_GNU_GETTEXT_REQUIRE_VERSION([0.19.8])
# XXX: We cannot remove the following macro due to backwards compatibility
# reasons. The above macro is set unconditionally to the minimal version
# required, and the below is set to 0.19.6, the first version introducing
# the AM_GNU_GETTEXT_REQUIRE_VERSION macro.
AM_GNU_GETTEXT_VERSION([0.19.6])
AM_GNU_GETTEXT([external])
DPKG_DIST_CHECK([test "$GMSGFMT" = ":" && test "$USE_NLS" = "yes"],
[gettext required when NLS support enabled])
# Shared libraries are disabled on purpose, currently there is no ABI stability
# guarantee, and it will be broken at will. The infrastructure is in place just
# to be able to test that its future activation will work.
AM_PROG_AR
LT_INIT([disable-shared])
DPKG_BUILD_SHARED_LIBS
DPKG_LINKER_AS_NEEDED
DPKG_LINKER_VERSION_SCRIPT
# Allow compilation without optional programs
DPKG_BUILD_PROG([dselect])
DPKG_BUILD_PROG([start-stop-daemon])
DPKG_BUILD_PROG([update-alternatives])
DPKG_BUILD_RELEASE_DATE
DPKG_BUILD_DEVEL_DOCS
# Allow alternate directories
DPKG_WITH_DIR([devlibdir], [${libdir}],
[dpkg development library directory [LIBDIR]])
DPKG_WITH_DIR([pkgconfdir], [${sysconfdir}/${PACKAGE_TARNAME}],
[dpkg configuration directory [SYSCONFDIR/dpkg]])
DPKG_WITH_DIR([docspecdir], [${docdir}/spec],
[dpkg specifications directory [DOCDIR/spec]])
DPKG_WITH_DIR([methodsdir], [${libexecdir}/${PACKAGE_TARNAME}/methods],
[dpkg download methods directory [LIBEXECDIR/dpkg/methods]])
DPKG_WITH_DIR([admindir], [${localstatedir}/lib/${PACKAGE_TARNAME}],
[dpkg database directory [LOCALSTATEDIR/lib/dpkg]])
DPKG_WITH_DIR([backupsdir], [${localstatedir}/backups],
[dpkg database backups directory [LOCALSTATEDIR/backups]])
DPKG_WITH_DIR([logdir], [${localstatedir}/log],
[system logging directory [LOCALSTATEDIR/log]])
DPKG_WITH_DIR([pkgconfigdir], [${devlibdir}/pkgconfig],
[pkg-config .pc fragments directory [DEVLIBDIR/pkgconfig]])
DPKG_WITH_DIR([aclocaldir], [${datadir}/aclocal],
[aclocal m4 fragments files directory [DATADIR/aclocal]])
DPKG_WITH_DIR([polkitactionsdir], [${datadir}/polkit-1/actions],
[polkit .policy actions directory [DATADIR/polkit-1/actions]])
DPKG_WITH_DIR([bashcompletionsdir], [${datadir}/bash-completion/completions],
[bash completions directory [DATADIR/bash-completion/completions]])
DPKG_WITH_DIR([zshcompletionsdir], [${datadir}/zsh/vendor-completions],
[zsh vendor completions directory [DATADIR/zsh/vendor-completions]])
# Set default dpkg-deb values
DPKG_DEB_COMPRESSOR([xz])
# Checks for programs.
DPKG_PROG_SHELL
DPKG_PROG_PAGER
AC_PROG_SED
AC_PROG_GREP
AC_PROG_EGREP
AC_PROG_CC
DPKG_C_STD([99])
AC_PROG_CXX
DPKG_CXX_STD([14])
DPKG_PROG_PATCH
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AC_CHECK_PROG([HAVE_DOT], [dot], [YES], [NO])
DPKG_PROG_TAR
DPKG_PROG_PO4A
DPKG_PROG_PERL
DPKG_PROG_POD2MAN
DPKG_CODE_COVERAGE
# Checks for operating system services and capabilities.
AC_SYS_LARGEFILE
# Checks for libraries.
DPKG_LIB_RT
DPKG_LIB_MD
DPKG_LIB_Z
DPKG_LIB_BZ2
DPKG_LIB_LZMA
DPKG_LIB_ZSTD
DPKG_LIB_SELINUX
AS_IF([test "$build_dselect" = "yes"], [
DPKG_LIB_CURSES
])
AS_IF([test "$build_start_stop_daemon" = "yes"], [
DPKG_LIB_SOCKET
DPKG_LIB_PS
DPKG_LIB_KVM
])
# Checks for header files.
AC_CHECK_HEADERS([\
error.h \
err.h \
locale.h \
xlocale.h \
libintl.h \
kvm.h \
sys/sysmacros.h \
sys/param.h \
sys/syscall.h \
sys/user.h \
sys/mkdev.h \
sys/pstat.h \
linux/fiemap.h \
])
AS_CASE([$host_os],
[linux-gnu*], [
# The glibc project has deprecated the <sys/sysctl.h> header and emits
# warnings on its usage, and removed it in 2.32. The Linux kernel removed
# support for it in 5.5.
], [
# On other systems, we need to check whether to use it.
AC_CHECK_HEADERS([\
sys/sysctl.h \
])
]
)
DPKG_CHECK_HEADER_SYS_PROCFS
AC_CHECK_HEADERS([sys/proc.h], [], [], [
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
])
AS_IF([test "$build_dselect" = "yes"], [
AC_LANG_PUSH([C++])
AC_CHECK_HEADERS([cxxabi.h])
AC_LANG_POP([C++])
])
# Checks for typedefs, structures, and compiler characteristics.
DPKG_ARCH_ABI
AC_C_CONST
AC_C_INLINE
AC_C_VOLATILE
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
DPKG_TYPE_PTRDIFF_T
DPKG_TYPE_STRUCT_PSINFO
DPKG_DECL_SYS_SIGLIST
DPKG_DECL_SYS_ERRLIST
# Checks for library functions.
DPKG_FUNC_VA_COPY
DPKG_FUNC_C99_SNPRINTF
DPKG_FUNC_FSYNC_DIR
DPKG_CHECK_DECL([offsetof], [stddef.h])
DPKG_CHECK_DECL([makedev], [sys/types.h])
DPKG_CHECK_DECL([WCOREDUMP], [sys/wait.h])
DPKG_CHECK_DECL([TIOCNOTTY], [sys/ioctl.h])
DPKG_CHECK_DECL([O_NOFOLLOW], [fcntl.h])
DPKG_CHECK_DECL([F_ALLOCSP64], [fcntl.h])
DPKG_CHECK_DECL([F_PREALLOCATE], [fcntl.h])
DPKG_CHECK_DECL([P_tmpdir], [stdio.h])
DPKG_CHECK_PROGNAME
DPKG_CHECK_COMPAT_FUNCS([\
getopt \
getopt_long \
obstack_free \
strchrnul \
strnlen \
strndup \
strerror \
strsignal \
asprintf \
fgetpwent \
fgetgrent \
scandir \
alphasort \
unsetenv \
])
AC_CHECK_FUNCS([\
lchown \
], [], [AC_MSG_ERROR([missing required function])])
AC_CHECK_FUNCS([\
setsid \
getdtablesize \
closefrom \
close_range \
getprocs64 \
getprogname \
getexecname \
lutimes \
fallocate \
posix_fallocate \
posix_fadvise \
uselocale \
])
AS_IF([test "$build_dselect" = "yes"], [
AC_LANG_PUSH([C++])
AC_CHECK_FUNCS([__cxa_pure_virtual])
AC_LANG_POP([C++])
])
DPKG_USE_MMAP
DPKG_USE_DISK_PREALLOCATE
# Checks for the build machinery.
AC_DEFINE([LIBDPKG_VOLATILE_API], [1], [Acknowledge the volatility of the API.])
DPKG_COMPILER_DIALECT
DPKG_COMPILER_HARDENING
DPKG_COMPILER_WARNINGS
DPKG_COMPILER_SANITIZER
DPKG_COMPILER_ANALYZER
DPKG_COMPILER_OPTIMIZATIONS
DPKG_LINKER_OPTIMIZATIONS
DPKG_ARCHITECTURE
AC_DEFINE([PACKAGE_RELEASE], [PACKAGE_VERSION " (" ARCHITECTURE ")"],
[Define the project release information, version and architecture])
AC_CONFIG_TESTDIR([src/at])
AM_MISSING_PROG([AUTOM4TE], [autom4te])
AC_CONFIG_FILES([
Makefile
dselect/Makefile
dselect/methods/Makefile
dselect/po/Makefile.in
lib/Makefile
lib/compat/Makefile
lib/dpkg/Makefile
lib/dpkg/libdpkg.pc
doc/Doxyfile
man/Makefile
po/Makefile.in
scripts/Build.PL
scripts/Makefile
scripts/README.cpan
scripts/mk/Makefile
scripts/po/Makefile.in
src/Makefile
src/at/atlocal
utils/Makefile
])
AC_CONFIG_HEADERS([config.h])
AC_OUTPUT
# Print the current configuration
cat <<CONFIG
Release:
Version . . . . . : $PACKAGE_VERSION
VCS id . . . . . : $PACKAGE_VCS_ID
Configuration:
Arch attributes:
cpu name . . . . . . . . . . : ${cpu_type}
os name . . . . . . . . . . . : ${os_type}
arch name . . . . . . . . . . : ${dpkg_arch}
arch bits . . . . . . . . . . : ${dpkg_arch_bits}
arch endian . . . . . . . . . : ${dpkg_arch_endian}
char bits . . . . . . . . . . : ${dpkg_char_bits}
char sign . . . . . . . . . . : ${dpkg_char_sign}
sizeof(short) . . . . . . . . : ${ac_cv_sizeof_short}
sizeof(int) . . . . . . . . . : ${ac_cv_sizeof_int}
sizeof(long) . . . . . . . . : ${ac_cv_sizeof_long}
sizeof(long long) . . . . . . : ${ac_cv_sizeof_long_long}
sizeof(float) . . . . . . . . : ${ac_cv_sizeof_float}
sizeof(double) . . . . . . . : ${ac_cv_sizeof_double}
sizeof(long double) . . . . . : ${ac_cv_sizeof_long_double}
sizeof(void *) . . . . . . . : ${ac_cv_sizeof_void_p}
sizeof(off_t) . . . . . . . . : ${ac_cv_sizeof_off_t}
sizeof(time_t) . . . . . . . : ${ac_cv_sizeof_time_t}
alignof(max_align_t) . . . . : ${ac_cv_alignof_max_align_t}
Features:
native language support . . . : $USE_NLS
unicode support . . . . . . . : $USE_UNICODE
development documentation . . : $build_devel_docs
code coverage . . . . . . . . : $enable_coverage
build shared libraries . . . : $enable_shared
mmap loaders . . . . . . . . : $enable_mmap
disk pre-allocation . . . . . : $enable_disk_preallocate
default dpkg-deb compressor . : $with_deb_compressor
default shell interpreter . . : $DPKG_SHELL
default pager program . . . . : $DPKG_PAGER
Paths:
devlibdir . . . . . . . . . . : $devlibdir
pkgconfdir . . . . . . . . . : $pkgconfdir
docspecdir . . . . . . . . . : $docspecdir
methodsdir . . . . . . . . . : $methodsdir
admindir . . . . . . . . . . : $admindir
backupsdir . . . . . . . . . : $backupsdir
logdir . . . . . . . . . . . : $logdir
pkg-config dir . . . . . . . : $pkgconfigdir
aclocal dir . . . . . . . . : $aclocaldir
polkit actions dir . . . . . : $polkitactionsdir
bash completions dir . . . . : $bashcompletionsdir
zsh completions dir . . . . . : $zshcompletionsdir
perl interpreter . . . . . . : $PERL
perl libdir . . . . . . . . . : $PERL_LIBDIR
Programs:
update-alternatives . . . . . : $build_update_alternatives
start-stop-daemon . . . . . . : $build_start_stop_daemon
dselect . . . . . . . . . . . : $build_dselect
System Libraries:
librt . . . . . . . . . . . . : $have_librt
libsocket . . . . . . . . . . : ${have_libsocket:-no}
libps . . . . . . . . . . . . : ${have_libps:-no}
libkvm . . . . . . . . . . . : ${have_libkvm:-no}
libselinux . . . . . . . . . : $have_libselinux
libmd . . . . . . . . . . . . : $have_libmd
libz . . . . . . . . . . . . : $have_libz_impl
liblzma . . . . . . . . . . . : $have_liblzma
libzstd . . . . . . . . . . . : $have_libzstd
libbz2 . . . . . . . . . . . : $have_libbz2
libcurses . . . . . . . . . . : ${have_libcurses:-no}
CONFIG

13
data/abitable Normal file
View file

@ -0,0 +1,13 @@
# Version=2.0
#
# This file contains the table of arch ABI attribute overrides.
#
# If the ABI is not present here then the attribute information for a
# Debian arch tuple matches the one on the cputable.
#
# - Column 1 is the Debian name for the ABI.
# - Column 2 is the size (in bits) of the ABI pointers.
#
# <Debian name> <Bits>
abin32 32
x32 32

54
data/cputable Normal file
View file

@ -0,0 +1,54 @@
# Version=1.0
#
# This file contains the table of known CPU names.
#
# Architecture names are formed as a combination of the system name
# (from ostable) and CPU name (from this table) after mapping from
# the Debian arch tuple (from tupletable).
#
# - Column 1 is the Debian name for the CPU, used to form the cpu part in
# the Debian arch tuple.
# - Column 2 is the GNU name for the CPU, used to output build, host and
# target variables in dpkg-architecture.
# - Column 3 is an extended regular expression used to fully match against
# the CPU part of the output of the GNU config.guess script. The order of
# this column is important when using wildcards as it is used in a first
# match basis.
# - Column 4 is the size (in bits) of pointers.
# - Column 5 is the endianness (byte ordering in numbers).
#
# <Debian name> <GNU name> <config.guess regex> <Bits> <Endianness>
alpha alpha alpha.* 64 little
amd64 x86_64 (amd64|x86_64) 64 little
arc arc arc 32 little
armeb armeb arm.*b 32 big
arm arm arm.* 32 little
arm64 aarch64 aarch64 64 little
hppa hppa hppa.* 32 big
loong64 loongarch64 loongarch64 64 little
i386 i686 (i[34567]86|pentium) 32 little
ia64 ia64 ia64 64 little
m68k m68k m68k 32 big
mips mips mips(eb)? 32 big
mipsel mipsel mipsel 32 little
mipsr6 mipsisa32r6 mipsisa32r6 32 big
mipsr6el mipsisa32r6el mipsisa32r6el 32 little
mips64 mips64 mips64 64 big
mips64el mips64el mips64el 64 little
mips64r6 mipsisa64r6 mipsisa64r6 64 big
mips64r6el mipsisa64r6el mipsisa64r6el 64 little
nios2 nios2 nios2 32 little
or1k or1k or1k 32 big
powerpc powerpc (powerpc|ppc) 32 big
powerpcel powerpcle powerpcle 32 little
ppc64 powerpc64 (powerpc|ppc)64 64 big
ppc64el powerpc64le powerpc64le 64 little
riscv64 riscv64 riscv64 64 little
s390 s390 s390 32 big
s390x s390x s390x 64 big
sh3 sh3 sh3 32 little
sh3eb sh3eb sh3eb 32 big
sh4 sh4 sh4 32 little
sh4eb sh4eb sh4eb 32 big
sparc sparc sparc 32 big
sparc64 sparc64 sparc64 64 big

View file

@ -0,0 +1,2 @@
*self_spec:
+ %{!r:%{!fpie:%{!fPIE:%{!fpic:%{!fPIC:%{!fno-pic:-fno-PIE}}}}}}

2
data/no-pie-link.specs Normal file
View file

@ -0,0 +1,2 @@
*self_spec:
+ %{!shared:%{!r:%{!fPIE:%{!pie:-fno-PIE -no-pie}}}}

41
data/ostable Normal file
View file

@ -0,0 +1,41 @@
# Version=2.0
#
# This file contains the table of known operating system names.
#
# Architecture names are formed as a combination of the system name
# (from this table) and CPU name (from cputable) after mapping from
# the Debian arch tuple (from tupletable).
#
# - Column 1 is the Debian name for the system, used to form the system part
# in the Debian arch tuple.
# - Column 2 is the GNU name for the system, used to output build, host and
# target variables in dpkg-architecture.
# - Column 3 is an extended regular expression used to fully match against
# the system part of the output of the GNU config.guess script. The order
# of this column is important when using wildcards as it is used in a first
# match basis.
#
# <Debian name> <GNU name> <config.guess regex>
eabi-uclibc-linux linux-uclibceabi linux[^-]*-uclibceabi
base-uclibc-linux linux-uclibc linux[^-]*-uclibc
eabihf-musl-linux linux-musleabihf linux[^-]*-musleabihf
base-musl-linux linux-musl linux[^-]*-musl
eabihf-gnu-linux linux-gnueabihf linux[^-]*-gnueabihf
eabi-gnu-linux linux-gnueabi linux[^-]*-gnueabi
abin32-gnu-linux linux-gnuabin32 linux[^-]*-gnuabin32
abi64-gnu-linux linux-gnuabi64 linux[^-]*-gnuabi64
spe-gnu-linux linux-gnuspe linux[^-]*-gnuspe
x32-gnu-linux linux-gnux32 linux[^-]*-gnux32
base-gnu-linux linux-gnu linux[^-]*(-gnu.*)?
eabihf-gnu-kfreebsd kfreebsd-gnueabihf kfreebsd[^-]*-gnueabihf
base-gnu-kfreebsd kfreebsd-gnu kfreebsd[^-]*(-gnu.*)?
base-gnu-kopensolaris kopensolaris-gnu kopensolaris[^-]*(-gnu.*)?
base-gnu-hurd gnu gnu[^-]*
base-bsd-darwin darwin darwin[^-]*
base-bsd-dragonflybsd dragonflybsd dragonfly[^-]*
base-bsd-freebsd freebsd freebsd[^-]*
base-bsd-netbsd netbsd netbsd[^-]*
base-bsd-openbsd openbsd openbsd[^-]*
base-sysv-aix aix aix[^-]*
base-sysv-solaris solaris solaris[^-]*
base-tos-mint mint mint[^-]*

2
data/pie-compile.specs Normal file
View file

@ -0,0 +1,2 @@
*self_spec:
+ %{!r:%{!fpie:%{!fPIE:%{!fpic:%{!fPIC:%{!fno-pic:%{!fno-PIE:%{!no-pie:-fPIE}}}}}}}}

2
data/pie-link.specs Normal file
View file

@ -0,0 +1,2 @@
*self_spec:
+ %{!static:%{!shared:%{!r:%{!fno-PIE:%{!no-pie:-fPIE -pie}}}}}

69
data/tupletable Normal file
View file

@ -0,0 +1,69 @@
# Version=1.0
#
# Bidirectional mapping between a Debian arch tuple and a Debian arch name.
#
# Debian arch tuple names are formed as a combination of the Debian system
# name (from the ostable) and the Debian CPU name (from the cputable) after
# applying the variable substitutions.
#
# Debian arch names are the result of historical naming conventions in Debian,
# where the predominant system architectures have many of their parts in
# implicit form, by only exposing the CPU with the ABI bolted on, where less
# common architectures have their OS part spelled out, and where even less
# common ones, have their libc spelled out. This table maps between the ideal
# architecture tuple, with the current messy reality.
#
# - Column 1 is the Debian arch tuple name, as the normalized form of the
# architecture names, used as the internal representation.
# - Column 2 is the Debian arch name, as the abbreviated form of the
# architecture names, used as the public interface.
#
# Supported variables: <cpu>
#
# <Debian arch tuple> <Debian arch name>
eabi-uclibc-linux-arm uclibc-linux-armel
base-uclibc-linux-<cpu> uclibc-linux-<cpu>
eabihf-musl-linux-arm musl-linux-armhf
base-musl-linux-<cpu> musl-linux-<cpu>
eabihf-gnu-linux-arm armhf
eabi-gnu-linux-arm armel
abin32-gnu-linux-mips64r6el mipsn32r6el
abin32-gnu-linux-mips64r6 mipsn32r6
abin32-gnu-linux-mips64el mipsn32el
abin32-gnu-linux-mips64 mipsn32
abi64-gnu-linux-mips64r6el mips64r6el
abi64-gnu-linux-mips64r6 mips64r6
abi64-gnu-linux-mips64el mips64el
abi64-gnu-linux-mips64 mips64
spe-gnu-linux-powerpc powerpcspe
x32-gnu-linux-amd64 x32
base-gnu-linux-<cpu> <cpu>
base-gnu-kfreebsd-amd64 kfreebsd-amd64
base-gnu-kfreebsd-i386 kfreebsd-i386
base-gnu-kopensolaris-amd64 kopensolaris-amd64
base-gnu-kopensolaris-i386 kopensolaris-i386
base-gnu-hurd-amd64 hurd-amd64
base-gnu-hurd-i386 hurd-i386
base-bsd-dragonflybsd-amd64 dragonflybsd-amd64
base-bsd-freebsd-amd64 freebsd-amd64
base-bsd-freebsd-arm freebsd-arm
base-bsd-freebsd-arm64 freebsd-arm64
base-bsd-freebsd-i386 freebsd-i386
base-bsd-freebsd-powerpc freebsd-powerpc
base-bsd-freebsd-ppc64 freebsd-ppc64
base-bsd-freebsd-riscv freebsd-riscv
base-bsd-openbsd-<cpu> openbsd-<cpu>
base-bsd-netbsd-<cpu> netbsd-<cpu>
base-bsd-darwin-amd64 darwin-amd64
base-bsd-darwin-arm darwin-arm
base-bsd-darwin-arm64 darwin-arm64
base-bsd-darwin-i386 darwin-i386
base-bsd-darwin-powerpc darwin-powerpc
base-bsd-darwin-ppc64 darwin-ppc64
base-sysv-aix-powerpc aix-powerpc
base-sysv-aix-ppc64 aix-ppc64
base-sysv-solaris-amd64 solaris-amd64
base-sysv-solaris-i386 solaris-i386
base-sysv-solaris-sparc solaris-sparc
base-sysv-solaris-sparc64 solaris-sparc64
base-tos-mint-m68k mint-m68k

2807
doc/Doxyfile.in Normal file

File diff suppressed because it is too large Load diff

35
doc/README.api Normal file
View file

@ -0,0 +1,35 @@
This is an (incomplete) list of currently provided APIs by dpkg, and
their supported status.
What: libdpkg.a (C static library)
Status: volatile
Description:
The API provided by this library is highly volatile, still in the process
of being cleaned up. It's only supposed to be used internally by dpkg for
now. Header files, functions, variables and types might get renamed,
removed or change semantics. If you still have a need to use it, which
you'd be doing anyway, say by locally building dpkg to get the library,
then define the C preprocessor macro LIBDPKG_VOLATILE_API in your build
to acknowledge that fact.
What: libdpkg-perl (perl modules)
Status: stable
Description:
Among the perl modules provided by libdpkg-perl, you can safely rely on
those that have $VERSION set to 1.00 (or higher). Note however that the
API is defined by what's documented in the corresponding manual pages and
nothing more. You can't assume anything else based on what you read in
the source code. If you feel the need for further refinements in the
documented API, don't hesitate to file a wishlist bug against
libdpkg-perl.
.
In case of API-breaking changes, the major number in $VERSION will be
increased. For API extensions, the minor number will be increased.
What: custom changelog parsers as Dpkg::Changelog derived modules
Status: stable
Description:
Since dpkg 1.18.8, custom changelog parsers are supported as modules
derived from the Dpkg::Changelog module. The derived modules need to
implement all required documented methods.

View file

@ -0,0 +1,180 @@
This is a list of features that are scheduled to be removed from dpkg.
What: fallback of dpkg-source to source format "1.0" without explicit debian/source/format
Status: deprecated
When: 1.17.x
Warning: program and lintian (missing-debian-source-format)
Why:
With the support of multiple source formats, the user should be explicit
about the desired source format. The fallback to "1.0" is there only for
backwards compatibility but will be removed once all packages have the
debian/source/format file. This is unlikely to happen before 1.17.x.
What --forget-old-unavail (dpkg option)
Status: obsolete
When: 1.16.x
Warning: program
Why:
Purged packages are properly cleaned up now by dpkg, and old unavailable
leftovers are automatically cleaned up on database parsing. So there's no
need anymore for this manual action.
What: --control-path (dpkg-query option)
Status: deprecated
When: 1.18.x
Warning: man page
This was a semi-public interface now superseded by --control-list and
--control-show, which are a better interface as they do not rely on any
specific database layout. Although there might still be cases where it's
required to avoid hardcoding the database layout, and it will be kept as
long as there's legitimate uses for it and no viable replacements.
What: -L (dpkg-parsechangelog option)
Status: obsolete
Since: 1.18.8
When: 1.19.x
Warning: program
Why:
The custom parsers have been switched from programs to perl modules,
and this option has no use any longer. The caller can set PERL5LIB or
PERLLIB to specify the perl module search path now.
History of feature removals
~~~~~~~~~~~~~~~~~~~~~~~~~~~
What: cleanup-info (program)
Status: removed
Since: 1.15.0
Why:
This program was needed long time ago to fixup broken info dir files
generated by buggy install-info programs. Should not be needed anymore.
What: --largemem, --smallmem (dpkg option)
Status: removed
When: 1.15.1
Why:
These options have been no-ops for a long time.
What: --force-auto-select (dpkg option)
Status: removed
When: 1.15.1
Why:
This option has been a no-op for so long, that there's no traces on git
history of its usage.
What: recommended, contrib, base (priority)
Status: removed
When: 1.15.1
Why:
These priorities have been superseded by either other fields or values in
other fields.
What: 822-date (program)
Status: removed
When: 1.15.1
Why:
Should switch to use 'date -R'.
What: support of custom changelog parsers understanding only -v
Status: removed
Since: 1.15.5
Why:
The debian changelog parser has been enhanced. It supports new options
that enable more fine-grained retrieval of information. Those new options
will be used by scripts (like dpkg-genchanges).
.
Custom changelog parsers must be updated to support the new API (see
dpkg-parsechangelog(1) and README.api).
What: support for environment variable DPKG_NO_TSTP
Status: removed
Since: 1.15.6
Why:
Having two ways to let the administrator get to a shell on conffile prompt
is confusing, it also impedes setting up a consistent environment to be
used by external programs.
What: support for PGP
Status: removed
When: 1.16.4
Warning: program
Why:
PGP is not part of Debian and GnuPG has been the standard tool for digital
signatures for several years already. Supporting only GnuPG enables us to
rely on some of its features.
What: -u, --udeb (dpkg-scanpackages option)
Status: removed
When: 1.16.4
Warning: program
Why:
This option has been superseded by -tudeb.
What: support for custom changelog parsers as programs
Status: removed
Since: 1.18.8
Why:
Using programs to implement the custom changelog parsers was very inefficient
as it required to parse the custom changelog, output deb822 formatted entries
to then parse that and output again with the desired format.
.
These were implemented as programs because at the time the perl code in dpkg
was not using perl modules, so it was not easy to extend. Using perl modules
now is cleaner and allows for a faster implementation.
.
In addition there's no known users in Debian, so it was deemed safe to remove
the support without a transition.
What: Source-Version (substvar)
Status: removed
When: 1.18.11
Warning: program, lintian (substvar-source-version-is-deprecated)
Why:
The semantics of Source-Version were misleading when applied to binNMUs.
Should switch to use binary:Version or source:Version substvars.
.
The code got changed to emit errors.
What: -Zlzma (dpkg-deb option value)
Status: removed
When: 1.18.11
Warning: program
Why:
LZMA compression has some format deficiencies fixed by XZ, which is what
upstream has replaced it with, as such there's no point in continuing to
support compressing new .deb files with that format, although unpacking
will be kept being supported to handle existing compressed files.
What: -Zbzip2 (dpkg-deb option value)
Status: removed
When: 1.18.11
Warning: program
Why:
bzip2 compression has been superseded by xz when it comes to size, and
gzip is still faster, in Debian there's really not many packages using
that compression, as such there's no point in continuing to support
compressing new .deb files with that format, although unpacking
will be kept being supported to handle existing compressed files.
What: --new, --old (dpkg-deb options)
Status: removed
When: 1.18.11
Warning: program
Why:
These options are not future-proof, and do not give the caller any
guarantee of what exact format version will be used to produce the
output file. They were replaced with a new --deb-format option.
What: --print-installation-architecture (dpkg option)
Status: removed
When: 1.18.11
Warning: program
Why:
Obsoleted long time ago (2005-01-22). Remaining packages should switch to
use 'dpkg --print-architecture'.
What: GCJ and GCJFLAGS support
Status: removed
When: 1.22.1
Why:
GCJ has been dead upstream since 2018.

334
doc/coding-style.txt Normal file
View file

@ -0,0 +1,334 @@
Dpkg POD coding style 2021-06-25
=====================
General
~~~~~~~
Verbatim code sections that need to be formatted, need to be prefixed with
a line containing exactly «Z<>», to trick the parser.
New sentences inside a paragraph should start on a new line, so that we
do not need to reflow the text when adding new content.
Every new feature, option or behavior change needs to be documented with
the version introducing the change.
Dpkg M4sh/Autoconf coding style 2016-09-05
===============================
General
~~~~~~~
All dpkg specific macros need to be prefixed with «DPKG_». Complex checks
should be defined as new macros under m4/dpkg-<name>.m4, and those used
in configure.ac which should look pretty simple.
Quoting and indentation
~~~~~~~~~~~~~~~~~~~~~~~
Code and arguments that wrap into the next line are indented by two spaces.
In principle all macro argument should always be quoted. Which brings one
of the biggest readability issues with M4sh/Autoconf code, the amount of
consecutive quotes and parenthesis pairs, which can make it very hard to
notice if they are unbalanced. To avoid this we use a style that tries to
avoid more than two consecutive blocks of «])».
We can either use a style resembling very simple function calls, when the
arguments are as well very simple, such as:
AC_DEFINE_UNQUOTED([SOME_VARIABLE],
[SOME_CONCOCTED_WAY_TO_GET_A_VALUE],
[Some descriptive text here])
AS_CASE([condition],
[case-a], [do-a],
[case-b], [do-b])
Or one resembling curly-braced C-style blocks, such as this:
AS_IF([condition], [
DO_SOMETHING([here])
], [
DO_OTHERWISE([there])
])
Except for AC_ARG_WITH, AC_ARG_ENABLE and AM_CONDITIONAL which need their
second argument quoted tightly surrounding the code, like this:
AC_ARG_ENABLE([feature],
[AS_HELP_STRING([--disable-feature], [Disable feature])],
[], [enable_feature="yes"])
AM_CONDITIONAL([HAVE_SOME_FEATURE],
[test "$ac_cv_have_some_feature" = "yes" && \
test "$ac_cv_have_some_feature" = "yes"])
or the output will get messed up.
Dpkg C/C++ coding style 2024-07-24
=======================
Standards
~~~~~~~~~
The C code base assumes C99, except for the following features:
- Variable length arrays.
- Mixed declaration and code.
The C++ code base assumes C++14.
The code base assumes a POSIX.1-2008 compatible environment.
The required features are checked at build time, and it will either use
compatibility code in case the needed extensions are not supported and it
is possible to support them, otherwise it will abort in case a needed one
cannot be used.
General
~~~~~~~
The coding style is a mix of parts from KNF [K] and the Linux CodingStyle [L].
If in doubt or missing from this file please ask, although files using the
tab based indentation can be considered canon.
[K] <https://www.freebsd.org/cgi/man.cgi?query=style>
[L] <https://kernel.org/doc/Documentation/process/coding-style.rst>
The code has a mix of an old coding style being phased out and the new
style. New files should use the new style, changes to files with the old
style should switch the code being touched except for the indentation level,
which should be preserved to match (2 spaces).
Code should generally strive for clarity. Monster functions should be split
into logical and small pieces.
Variable and function names should be generally descriptive, not needed
for variables commonly used (for example an index inside a loop, etc),
acronyms should only be used if they are widely known externally or
inside the project. The names should separate logical concepts within
with underscores.
On comments use UTF-8 characters for quotes, copyright symbols, etc.
On strings in code use simple or double quotes «''» «""». Not the unpaired
ones «`'». Strings marked for translation, should only be fixed if there's
other changes to be done on them, otherwise we get unneeded fuzzies.
<https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html>
Code documentation
~~~~~~~~~~~~~~~~~~
Public declarations should be documented using JavaDoc style comments.
Documentation should always be close to its definition (usually in the .c
or .cc files) and not its declaration, so that when the code changes it's
less likely that they will get out of sync. For data types, macros and
similar where there's only declarations, the documentation will usually
go instead in the header files.
For enum values and struct members, the documentation should usually be
one-line comments, preceding the item.
The comment title should be on the second line on its own, and the long
description on its own paragraph.
Examples:
/**
* This is the enum title.
*/
enum value_list {
/** Value doing foo. */
VALUE_A,
/** Value doing bar. */
VALUE_B,
};
/**
* This is the title.
*
* This is the long description extending several lines, explaining in
* detail what this item does.
*
* @param a This is the a parameter.
* @param b This is the b parameter.
*
* @return This is the return value.
*/
Indentation, alignment and spacing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lines should be 80 chars max. Indentation is done with hard tabs (which
should be considered to take 8 spaces width). Aligning with spaces:
static void
function(void *ptr, int value)
{
void *ref_ptr = get_ref(ptr);
int ref_value = get_value(ref);
if (value > 10)
do_something(GLOBAL_MACRO, ptr, value, "some-string",
ref_ptr, ref_value, "other-string",
"extra-string");
}
When wrapping, logical operators should be kept on the preceding line:
if (really_long_variable_to_be_checked_against_a &&
really_long_variable_to_be_checked_against_b)
foo();
Spaces around operators:
if (a && (b || c) && c == d)
break;
a = (b + 4 * (5 - 6)) & 0xff;
Spaces around assignments:
a += b;
Spaces after comma:
foo(a, b);
Space after keywords (for, while, do, if, etc, but sizeof should be
treated like a function):
for (i = 0; i < 10; i++)
foo(i);
memcpy(dst, src, sizeof(src));
Definition of local variables, related code blocks, functions bodies
should be split with blank lines:
int
function(void)
{
int a;
foo();
bar();
quux();
return 0;
}
Braces
~~~~~~
Braces should be placed on the same line as the keyword, but on a new line
for the function body. No braces should be used for unambiguous one line
statements:
if (a > 0) {
foo(a);
bar(a);
} else {
quux(0)
bar(0);
}
for (;;) {
foo();
bar();
}
do {
foo();
bar();
} while (quux());
switch (foo) {
case a:
bar();
break;
case b:
default:
baz();
break;
}
Code conventions
~~~~~~~~~~~~~~~~
Prefer assigning outside of conditionals:
n = read_items();
if (n < 100)
foo();
String comparisons should use comparison operators to make it easier to
see what operation is being done:
if (strcmp(a, b) == 0)
foo();
if (strcmp(a, b) < 0)
foo();
Dpkg Perl coding style 2019-03-27
======================
Perl version
~~~~~~~~~~~~
We don't want to impose a too-recent Perl version, so only use features
supported by the Perl version that is currently in Debian oldstable when
possible. Currently that means Perl 5.32.1.
General
~~~~~~~
In general you should follow the conventions listed in perlstyle(1).
All the code should run with the “use strict” and “use warnings” pragmas,
and pass «make authorcheck».
Code documentation
~~~~~~~~~~~~~~~~~~
Public modules should be documented with POD (see perlpod(1)). Private
code doesn't have to use POD, simple comment lines (starting with "#") are
enough, but if they use POD they need to note the fact that the module is
private in the CHANGES section and specify a version «0.xx». Public scripts
are documented in their corresponding manual pages.
Indentation, alignment and spacing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lines should be 80 chars max. The indentation level is 4 characters, and
indentation is done with soft tabs (no hard tabs) and spaces.
if ($foo) {
if ($bar) {
print "Hello\n";
unless ($baz) {
print "Who are you?\n";
}
}
}
Object methods
~~~~~~~~~~~~~~
Use a single line to retrieve all the arguments and use $self as name
for the current object:
sub do_something {
my ($self, $arg1, $arg2, %opts) = @_;
...
}
Supplementary optional arguments should be named and thus stored in a
hash.

44
doc/spec/build-driver.txt Normal file
View file

@ -0,0 +1,44 @@
Support for build-drivers as alternatives to debian/rules
=========================================================
Status: draft, experimental
Summary
-------
This is currently an exploratory and experimental way to replace the current
debian/rules usage with alternative interfaces for building packages.
It relies on a new Build-Driver field honored by dpkg-buildpackage, but that
might eventually disappear or change semantics.
Background
----------
Our current packaging methods are built around the concept of a Makefile
(debian/rules), which must contain every bit of logic needed to produce
debs. Historically, this involved duplicating various runes in every
package and then spending decades updating the runes in every package
as we got wiser. Over time there have been many attempts to centralize
these runes in package helpers such as debstd (obsolete), dbs (obsolete),
yada (obsolete), debhelper (still in use) and cdbs (still in use).
Despite these improvements, our state of the art packaging flow suffers
from this awkward "assume-nothing-do-everything" design. There are many
cases where dpkg has the only "official" tools to implement a feature
(e.g. dpkg-gencontrol and dpkg-deb), but we still expect that the helper
tools manage all orchestration of calling these tools in the right order.
Furthermore, the "Makefile as an entry point" also neuters any efficient
communication between dpkg tools and the underlying helper, as it
introduces an impedance layer which forces us to reparse the same files
multiple times, does not make it possible to guarantee a sanitized build
environment for the packaging, complicates our ability to enable certain
features transparently or (in debhelper's case) via compat bumps, and
also forces us into imperative packaging flows (making it difficult for
lintian to spot issues). As "recent" examples we can mention "build-arch"
targets, updating XXFLAGS to include basic hardening, and the
Rules-Requires-Root field.
All of these things complicate the lower packaging stack, inhibits our
ability to deploy various performance optimizations and neuters our
ability to make packaging simpler.

30
doc/spec/frontend-api.txt Normal file
View file

@ -0,0 +1,30 @@
Frontend Interfaces
===================
Status: recommendation, stable
Overview
--------
This file will try to document some of the interfaces that dpkg makes
available to frontends or that expects them to use, which are currently
not covered by any other type of documentation.
Database Locking
----------------
Any frontend needing to make sure no write operation is currently happening,
and no other frontend is running should first acquire the frontend lock at
«<admindir>/lock-frontend», and then acquire the dpkg database lock at
«<admindir>/lock». When the frontend invokes dpkg, it should set the
environment variable DPKG_FRONTEND_LOCKED (to prevent dpkg from acquiring
the frontend lock), and then release the dpkg database lock, which will be
acquired by dpkg itself. This way no other frontend following this protocol
can race to perform operations while another one has one in progress.
These locks must be file record locks (i.e. fcntl(2) advisory locking), and
the whole file should be locked, as that's the most portable way to perform
this operation; this can be achieved by using start=0, len=0 and
whence=SEEK_SET.

View file

@ -0,0 +1,74 @@
Support for a Protected field
=============================
Status: draft, experimental
URL: https://wiki.debian.org/Teams/Dpkg/Spec/ProtectedField
Summary
-------
The goal of the following proposal is to standardize a field to split
part of the «Essential» packages, and add support for it in the package
management stack. There is currently an Important field, that has the
correct semantics but has a very confusing name and is only supported
by apt anyway, so this new field would phase out that one.
Background
----------
Our current use of «Essential: yes» is confused, and it includes several
conflated things, some of which would be worth splitting up.
We use «Essential» to:
* Denote that a package must be always installed and cannot be
removed (easily), because it is essential to the system in some way.
* Denote that a package must be functional even when just unpacked
(after having been configured once / fully bootstrapped).
* Mark auto-vivification, by making front-ends either complain very
loudly or reinstalling these packages when missing.
* Minimize dependency loops, by making these dependencies implicit.
One problem is that the first point above includes being essential for
the packaging system during upgrades/installation, for the operation
of the system in general, and for the operation of the system during
boot.
The latter is not always necessary though, for example within a chroot,
or some types of containers. There has been work on trying to trim down
the pseudo-essential set as can be seen from:
<https://wiki.debian.org/Proposals/EssentialOnDiet>
<https://wiki.debian.org/BusterPriorityRequalification>
And several of these switches made use of a pre-existing field called
«Important», defined and currently only supported by apt, which had the
following properties:
* These packages are not required to be installed.
* They do not have to be usable while unconfigured.
* Dependencies need to be spelled out.
Proposal
--------
The proposal would be to add support for a new Protected field, with the
following properties:
* Protected packages should not be trivial to remove (require a force
option for example, like «Essential»).
* Protected packages should not be required to be installed (i.e. once
removed they should not be automatically brought back by a front-end,
unlike «Essential»).
* Protected packages must be depended on explicitly (unlike «Essential»).
* Protected packages must be functional even when unpacked (think of
a boot loader or an init system; like «Essential»). [XXX: This one is
not entirely clear and might not match reality anyway, for example kernels,
which might require building an initramfs, etc.]
This would make it possible to phase out the current «Important» field
usage (because it has a name too confusing relative to the «Priority»
value; and has small tooling coverage) and the usage of «Essential» for
at least packages involved in the boot process, and perhaps also for
packages essential for operation of the system in general (in contrast
to packages required for the packaging system).

View file

@ -0,0 +1,179 @@
Supporting rootless builds
==========================
Status: recommendation, stable
Version: 1.0
Background
----------
Traditionally, Debian packages have required (fake)root privileges for some
of the "debian/rules" targets. This has required also a split between build
and binary targets; making the builds slower, due to the increased amount
of invocations of "debian/rules" and the overhead of using fakeroot(1) or
equivalent fake environments, or less secure due to the increased dangers
of running under real root via sudo or equivalent.
On this document when talking about "(fake)root" privileges, it will refer
to any mechanism, supported by the dpkg-buildpackage "-r/--root-command"
option, that can provide either a real or faked root user environment.
Specification
-------------
We add a new field to the "Source" stanza of debian/control:
Rules-Requires-Root: no | binary-targets | <implementations-keywords>
The case sensitive values are defined as:
* If "no", then "debian/rules binary" will not require root at all (not even
fakeroot). This is the default in dpkg-build-api level >= 1, or since
dpkg 1.22.13.
- If the "no" keyword is used, it MUST be the only keyword in that field
and MUST appear exactly once.
* If "binary-targets", then "debian/rules binary" (etc.) must always be run
under (fake)root. This was the status quo, default in dpkg-build-api level 0
until dpkg 1.22.13.
* <implementations-keywords> will be a space separated list of keywords which
define when root is required.
- Keywords consists of <namespace>/<cases>. The "namespace" part cannot
contain "/" or whitespace. The "cases" part cannot contain whitespace.
Furthermore, both parts MUST consist entirely of printable ASCII
characters.
- Each tool/package will define a namespace named after itself and provide
a number of cases where (fake)root is required.
(See also "Implementation provided keywords".)
- When "Rules-Requires-Root" is set to <implementations-keywords>, the
builder (i.e. whatever is executing debian/rules) will expose an
interface that is used to run a command under (fake)root via the
"Gain Root API". If the builder cannot provide such a command, it
MUST behave like "Rules-Requires-Root" was set to "binary-targets",
i.e. run "debian/rules binary" under (fake)root.
When the builder supports this specification, it MUST notify this fact to
the rules file via the "DEB_RULES_REQUIRES_ROOT" environment variable, with
the value it has obtained from the Rules-Requires-Root field or some builder
specific override mechanism, which will denote the level of support the
builder has chosen to commit to take effect during the build. When set,
it MUST be a valid value for the Rules-Requires-Root field. If unset,
the build system SHOULD assume that the builder does not recognize the
Rules-Requires-Root field at all.
It is always permissible for a builder to ignore this field and fall back to
running the binary targets under (fake)root. This is to ensure backwards
compatibility when builds are performed by legacy builders or older versions
of the tooling.
Tools called from the rules file MUST cope gracefully with being called under
(fake)root even when Rules-Requires-Root is set to a value that implies they
should not be (e.g. "no"). However, they MUST NOT attempt to run processes
under (fake)root when run as a regular user when Rules-Requires-Root does
not list any keywords they respond to.
Tools MUST gracefully ignore valid unknown keywords outside their namespace.
They MAY warn about unknown keywords inside their namespace.
The value of this field MUST NOT change the content of the package in any
way. Notably, packages that are bit-for-bit reproducible MUST still provide
bit-for-bit identical results even when the field is ignored.
Implementation provided keywords
--------------------------------
Keywords provided by various implementations:
* dpkg/target-subcommand: When the package needs to run a given command
under (fake)root within the "debian/rules" files directly, this MUST be
declared via this keyword.
* dpkg/target/<target-name>: When a specific "debian/rules" unofficial
target (none of the root-requiring "binary-indep", "binary-arch", "binary",
"clean", nor the non-root-requiring "build-indep", "build-arch", "build")
needs to be run under (fake)root, this MUST be declared via this dynamic
keyword, where <target-name> is the name of the "debian/rules" target.
* debhelper/upstream-make-install: The dh_auto_install command will run
the "install" target from the upstream's Makefile under (fake)root (for
the "makefile" build system or one derived from it).
Gain Root API
-------------
The builder will provide a command to promote a given command to (fake)root
by exposing it in the environment variable "DEB_GAIN_ROOT_CMD". Tools that
need this promotion will then use it like the following:
$DEB_GAIN_ROOT_CMD cmd-that-needs-root ...
This command is subject to the same requirements as the "gain-root-command"
that dpkg-buildpackage accepts via its "-r/--root-command" option, which
means that it can contain space-separated parameters. If dpkg-buildpackage is
called with "-r/--root-command", then dpkg-buildpackage shall use that value
as the value for "DEB_GAIN_ROOT_CMD". The command SHOULD preserve all the
environment variables, unmodified.
The variable SHOULD only be provided when there is a need for it. Notably
when "Rules-Requires-Root" is either "no" or "binary-targets" the variable
SHOULD NOT be defined.
(The "DEB_GAIN_ROOT_CMD" variable used to be named "DPKG_GAIN_ROOT_CMD"
starting with dpkg 1.19.0 and before dpkg 1.19.1 when this specification
got released as stable. The old name MUST not be used.)
Common cases
------------
* Upstream installation insists on "sudo make install"-like behavior.
=> Use dpkg/target-subcommand or debhelper/upstream-make-install.
* Files shipped in the package must be owned by another user than root.
=> Not covered; use "binary-targets" for now until dpkg+debhelper
provides the required interface.
Prototyping/preparation
=======================
dpkg side
---------
dpkg-deb --build provides the --root-owner-group option so that dh_builddeb
or direct calls can control the owner/group file values w/o requiring
(fake)root.
dpkg-buildpackage must export DEB_GAIN_ROOT_CMD when necessary (for
prototyping, doing this unconditionally would be fine).
debhelper side
--------------
When the field is present:
* dh_testroot will behave as usual when Rules-Requires-Root is not present
or set to "binary-targets".
* dh_testroot will be a no-op when Rules-Requires-Root is set to "no".
* Otherwise, dh_testroot will either verify that it is run under (fake)root
(as usual) OR assert that DEB_GAIN_ROOT_CMD is defined.
* debhelper build systems will be patched to check for the
"debhelper/upstream-make-install" keyword and use the "Gain Root API"
accordingly.
* All other (src:)debhelper commands will skip their calls to chown
(currently they just reset them to "0:0" anyway).
With the above, a default "dh $@" will no longer require (fake)root when
built (and Rules-Requires-Root is "no").
Prototyping:
* During prototyping, dh_builddeb can wrap the dpkg-deb --build call with
fakeroot (when not already root).

818
doc/spec/triggers.txt Normal file
View file

@ -0,0 +1,818 @@
Triggers
========
Status: recommendation, stable
Introduction
------------
A dpkg trigger is a facility that allows events caused by one package
but of interest to another package to be recorded and aggregated, and
processed later by the interested package. This feature simplifies
various registration and system-update tasks and reduces duplication
of processing.
(NB: Triggers are intended for events that occur during package
installation, not events that occur in general operation.)
Concepts
--------
Each trigger is named, and at any time zero or more packages may be
interested in it.
We currently envisage three kinds of triggers:
* Explicit triggers. These can be activated by any program
by running dpkg-trigger (at any time, but ideally from a maintainer
script).
* File triggers. These are activated automatically by dpkg
when a matching file is installed, upgraded or removed as part
of a package. They may also be explicitly activated by running
dpkg-trigger.
* Future kinds of special triggers, which are activated by magic code
in dpkg itself. Currently none are defined besides file triggers.
A trigger is always activated by a particular package.
Trigger names contain only printing 7-bit ASCII characters (no
whitespace). Each trigger kind has a distinct subset of the trigger
name space so that the kind can be determined from the name. After we
run out of straightforward syntaxes, we will use <kind>:<details>.
When a trigger is activated, it becomes pending for every package
which is interested in the trigger at that time. Each package has a
list of zero or more pending triggers. Repeated activation of the
same trigger has no additional effect. Note that in general a trigger
will not be processed immediately when it is activated; processing is
deferred until it is convenient (as described below).
At a trigger activation, the interested packages(s) are added to the
triggering package's list of triggers-awaited packages (unless the
trigger has been configured to not require it); the triggering
package is said to await the trigger processing.
A package which has pending triggers, or which awaits triggers, is not
considered properly installed. There are two new dpkg status values,
triggers-pending and triggers-awaited, which lie between
config-failed and installed.
Details - Overview table
------------------------
Status Pending Awaited Satisfies Remedy
triggers triggers Depends
unpacked never maybe No postinst configure
c.-failed never maybe No postinst configure (when requested)
t.-awaited yes always No postinst triggered + fix awaited pkg(s)
t.-awaited no always No fix awaited package(s)
t.-pending always never Yes postinst triggered
installed never never Yes n/a
Packages in t-awaited and t-pending demand satisfaction of their
dependencies just like packages in installed.
Details - triggering package
----------------------------
When a package <T> activates a trigger in which a package <I> is
interested, <I> is added to the list of packages whose trigger
processing is awaited by <T>. Zero or more packages <I> may be added as a
result of any particular trigger activation, depending on how many
packages were interested. (If <T> chooses, explicit trigger activation
using dpkg-trigger of <I> by <T> need not make <T> become triggers-awaited
in this way.)
A package which awaits trigger processing but would otherwise be
installed or triggers-pending is considered to be in state
triggers-awaited. Packages in triggers-awaited do not satisfy
Depends dependencies.
Every triggered package <I> in <T>'s list of awaited packages either has a
nonempty list of pending triggers, or is in config-failed or worse.
When <I> enters installed (or config-files or not-installed), the
entry in <T>'s list of awaited packages is removed so that <T> may, if it
no longer awaits any packages, become installed or triggers-pending.
Packages in config-files or not-installed do not await triggers.
Details - triggered package
---------------------------
When one of the triggers in which a package is interested is
activated, the triggered package has the trigger added to its list of
pending triggers. Packages with a nonempty list of pending triggers
which would otherwise be in state installed are in state
triggers-pending instead, so if the package was previously
installed it becomes triggers-pending.
If a package has nonempty lists both of pending and awaited triggers,
then it is in triggers-awaited. Nevertheless efforts will still be
made to process its triggers so as to make the list of pending
triggers empty.
To restore a package in state triggers-pending to installed, or to
process pending triggers of a package with both pending and awaited
triggers, dpkg will run the postinst script as:
postinst triggered "<trigger-name> <trigger-name> ..."
by passing a space-separated list of <trigger-name>s as the second argument.
This will be attempted for each relevant package at the end of each
dpkg run; so, normally, in the same dpkg run as the event which made
the package go to triggers-pending. This leaves packages in
reasonable states by default.
If the “postinst triggered” run fails the package goes to
config-failed, so that the trigger processing will not be attempted
again until explicitly requested.
v
┌────────────┐
│ unpacked │
└─────┬──────┘
(automatic)│ ┌───────────────┐
│ │ config-failed │
│ └─────┬─────────┘
│ │ ^
│ │ │
├──────<─────┘ │ ┌──────────────────────────────────┐
│ (user request) │ │ triggers-pending │
postinst │ │ │ or │
"configure" │ │ │ triggers-awaited w/ some pending │
│ │ └────────────┬─────────────────────┘
│ │ │ ^
├────────>───────┤ postinst │ │
│ error │ "triggered" │ │
│ │ (automatic) │ │
│ │ │ │ trigger(s)
│ │ │ │ activated
│ └────────<─────────┤ │
│ error │ │
│ │ │
v v │
┌──────────────────────────────────────────────┴────┐
│ installed or triggers-awaited w/ none pending │
└───────────────────────────────────────────────────┘
Packages in config-failed or worse are never considered to have
lists of pending triggers. A package whose postinst is being run
can however acquire pending triggers during that run (ie, a package
can trigger itself).
This means that if a triggering package <T> awaits trigger processing by
an interested package <I>, and <I> goes to config-failed or worse (eg,
during unpack for upgrade), then when <I> is reconfigured (goes to
installed) or removed, <T> will no longer await processing by <I>, so
that <T> may automatically go from triggers-awaited to installed.
Or to put it another way, triggered actions are considered irrelevant
if the interested package <I> is not configured. When <I>'s postinst is
called with configure, it must do whatever actions are necessary to
deal with any trigger activations which might have occurred while it
was not configured, just as if the package was being configured for
the first time.
Trigger processing should be idempotent. The list of triggers being
processed is provided to the postinst only so that it can optimize
away redundant processing.
In that case, where an interested package has more than one trigger
and wants to process them differently, the list of triggers can
be examined in a shell script like this:
case " $2 " in
*" trigger-name-a "*) process-trigger-a ;;
esac
Generally each trigger name should be tested for separately, as the
postinst will often be called for several triggers at once.
Note that if a package both activates triggers in other packages, and
is interested in triggers of its own, its postinst may run for trigger
processing before the postinst(s) of the package(s) it has triggered.
Timing guarantees, races, etc.
------------------------------
Activating a trigger will not have any immediate effect, although
putative resulting status changes will show up in dpkg --status etc.
(Putative because the actual status changes may depend on the state of
trigger interests when dpkg processes the trigger activation into
the status database, rather than that when dpkg --status is run.)
A package is only guaranteed to become notified of a trigger
activation if it is continuously interested in the trigger, and never
in config-failed or worse, during the period from when the trigger
is activated until dpkg runs the package postinst (either due to
--configure --pending, or at the end of the relevant run, as described
above). Subsequent to activation and before notification, the
interested package will not be considered in state installed, so
long as the package remains interested, and the triggering package
will not be considered installed.
If the package is not in state installed, triggers-pending or
triggers-awaited then pending triggers are not accumulated.
However, if such a package (between half-installed and
config-failed inclusive) declares some trigger interests then the
triggering packages *will* await their configuration (which implies
completion of any necessary trigger processing) or removal.
It is not defined in what order triggers will run. dpkg will make
some effort to minimize redundant work in the case where many packages
have postinst trigger processing activating another package's triggers
(for example, by processing triggers in fifo order during a single
dpkg run). Cycles in the triggering graph are prohibited and will
eventually, perhaps after some looping, be detected by dpkg and cause
trigger processing to fail; when this happens one of the packages
involved will be put in state config-failed so that the trigger loop
will not be reattempted. See “Cycle detection” below.
Explicit triggers
-----------------
Explicit triggers have names with the same syntax as package names,
*but* should *not* normally be named identically to a package.
When choosing an explicit trigger name it is usually good to include a
relevant package name or some other useful identifier to help make the
trigger name unique. On the other hand, explicit triggers should
generally not be renamed just because the interested or triggering
packages' names change.
Explicit trigger names form part of the interface between packages.
Therefore in case of wider use of any trigger the name and purpose
should be discussed in the usual way and documented in the appropriate
packaging guidelines (eg, in the distribution policy).
File triggers
-------------
File triggers have names of the form
/path/to/directory/or/file
and are activated when the specified filesystem object, or any object
under the specified subdirectory, is created, updated or deleted by
dpkg during package unpack or removal. The pathname must be absolute.
File triggers should not generally be used without mutual consent.
The use of a file trigger, and the name of the trigger used, should be
stated in the distribution policy, so that a package which creates a
relevant file in a maintainer script can activate the trigger explicitly.
File triggers must definitely not be used as an escalation tool in
disagreements between different packages as to the desired contents of
the filesystem. Trigger activation due to a particular file should
not generally modify that file again.
Configuration files (whether dpkg-handled conffiles or not), or any
other files which are modified at times other than package management,
should not rely on file triggers detecting all modifications; dpkg
triggers are not a general mechanism for filesystem monitoring.
If there are or might be directory symlinks which result in packages
referring to files by different names, then to be sure of activation
all of the paths which might be included in packages should be listed.
The path specified by the interested package is matched against the
path included in the triggering package, not against the truename of
the file as installed. Only textually identical filenames (or
filenames where the interest is a directory prefix of the installed
file) are guaranteed to match.
A file trigger is guaranteed to be activated before the file in
question is modified by dpkg; on the other hand, a file trigger might
be activated even though no file was actually modified. Changes made
by dpkg to the link count of a file, or to solely the inode number
(ie, if dpkg atomically replaces it with another identical file), are
not guaranteed to cause trigger activation.
Because of the restriction on trigger names, it is not possible to
declare a file trigger for a directory whose name contains whitespace,
i18n characters, etc. Such a trigger should not be necessary.
Package declarations regarding triggers
---------------------------------------
See deb-triggers(5).
Support future extension of the trigger name syntax with additional
dpkg-generated triggers is as follows: a package which is interested
in any unsupported trigger kinds cannot be configured (since such a
package cannot be guaranteed to have these triggers properly activated
by dpkg). Therefore no package can be interested in any unsupported
trigger kinds and they can be freely activated (both by activate and
by dpkg-trigger). dpkg-deb will be changed to warn about unrecognized
trigger names syntaxes and unrecognized trigger control directives.
New command line interfaces to dpkg tools
-----------------------------------------
See dpkg(1).
Here is a summary of the behaviors:
Command line Trigproc Trigproc Configure
these any triggered
----------------------+---------------+---------------+-----------------
--unpack no usually[1] none
--remove n/a usually[1] none
--install n/a usually[1] these
--configure -a any needed usually[1] any needed
--configure <some> if needed usually[1] must, or trigproc
--triggers-only -a any needed usually[1] none
--triggers-only <some> must usually not[1] none
[1] can be specified explicitly by --triggers or --no-triggers
See dpkg-trigger(1).
A trigger may be activated explicitly with:
dpkg-trigger [--by-package <package>] <name-of-trigger>
dpkg-trigger --no-await <name-of-trigger>
There will be no output to stdout, and none to stderr unless
dpkg-trigger is unable to make a record of the trigger activation.
NB that in the case of a file trigger the name of the trigger is
needed, not the name of a file which would match the trigger.
apt and aptitude
----------------
These must be taught about the new triggers-awaited and
triggers-pending states. Packages in these states should be treated
roughly like those in unpacked: the remedy is to run dpkg
--configure.
Normally apt and aptitude will not see packages in triggers-pending
since dpkg will generally attempt to run the triggers thus leaving the
package in config-failed or installed.
Note that automatic package management tools which call dpkg (like apt
and aptitude) should not attempt to configure individual packages in
state triggers-pending (or indeed triggers-awaited) with dpkg
--triggers-only <package>... or dpkg --no-triggers --configure <package>...,
or similar approaches. This might defeat dpkg's trigger cycle detection.
A package management tool which will run dpkg --configure --pending at
the end may use --no-triggers on its other dpkg runs. This would be
more efficient as it allows more aggressive deferral (and hence more
unification) of trigger processing.
Error handling
--------------
Packages should be written so that they DO NOT BREAK just because
their pending triggers have not yet been run. It is allowed for the
functionality relating to the unprocessed trigger to fail (ie, the
package which is awaiting the trigger processing may be broken), but
the remainder of the interested package must work normally.
For example, a package which uses file triggers to register addons
must cope with (a) an addon being dropped into the filesystem but not
yet registered and (b) an addon being removed but not yet
deregistered. In both of these cases the package's main functionality
must continue to work normally; failure of the addon in question is
expected, warning messages are tolerable, but complete failure of the
whole package, or failures of other addons, are not acceptable.
dpkg cannot ensure that triggers are run in a timely enough manner for
pathological error behaviors to be tolerable.
Where a trigger script finds bad data provided by a triggering
package, it should generally report to stderr the problem with the bad
data and exit nonzero, leaving the interested package in config-failed
and the triggering package in triggers-awaited and thus signalling the
problem to the user.
Alternatively, in some situations it may be more desirable to allow
the interested package to be configured even though it can only
provide partial service. In this case clear information will have to
be given in appropriate places about the missing functionality, and a
record should be made of the cause of the errors. This option is
recommended for situations where the coupling between the interested
and triggering package is particularly loose; an example of such a
loose coupling would be Python modules.
WORKED EXAMPLE - SCROLLKEEPER
=============================
Currently, every Gnome program which comes with some help installs the
help files in /usr/share/gnome/help and then in the postinst runs
scrollkeeper-update. scrollkeeper-update reads, parses and rewrites
some large xml files in /var/lib/scrollkeeper; currently this
occurs at every relevant package installation, upgrade or removal.
When triggers are available, this will work as follows:
* gnome-foobar will ship its «omf» file in /usr/share/omf as
normal, but will not contain any special machinery to invoke
scrollkeeper.
* scrollkeeper will in its triggers control file say:
interest /usr/share/omf
and in its postinst say:
scrollkeeper-update-now -q
dpkg will arrange that this is run once at the end of each run
where any documentation was updated.
Note that it is not necessary to execute this only on particular
postinst "$1" values; however, at the time of writing, scrollkeeper
does this:
if [ "$1" = "configure" ]; then
printf "Rebuilding the database. This may take some time.\n"
scrollkeeper-rebuilddb -q
fi
and to retain this behavior, something along the following lines
would be sensible:
if [ "$1" = "configure" ]; then
printf "Rebuilding the database. This may take some time.\n"
scrollkeeper-rebuilddb -q
else
printf "Updating GNOME help database.\n"
scrollkeeper-update-now -q
fi
* dh_scrollkeeper will only adjust the DTD declarations and no longer
edit maintainer scripts.
Full implementation of the transition plan defined below, for
scrollkeeper, goes like this:
1. Update scrollkeeper:
- Add a triggers control archive file containing
interest /usr/share/omf
- Make the postinst modifications as described above.
- Rename scrollkeeper-update to scrollkeeper-update-now
- Provide a new wrapper script as scrollkeeper-update:
#!/bin/sh
set -e
if type dpkg-trigger >/dev/null 2>&1 && \
dpkg-trigger /usr/share/omf; then
exit 0
fi
exec scrollkeeper-update-now "$@"
2. In gnome-policy chapter 2, “Use of scrollkeeper”,
- delete the requirement that the package must depend on
scrollkeeper
- delete the requirement that the package must invoke
scrollkeeper in the postinst and postrm
- instead say:
OMF files should be installed under /usr/share/omf in the
usual way. A dpkg trigger is used to arrange to update the
scrollkeeper documentation index automatically and no special
care need be taken in packages which supply OMFs.
If an OMF file is placed, modified or removed other than as
a file installed in the ordinary way by dpkg, the dpkg file
trigger «/usr/share/omf» should be activated; see the dpkg
triggers specification for details.
Existing packages which Depend on scrollkeeper (>= 3.8)
because of dh_scrollkeeper or explicit calls to
scrollkeeper-update should be modified not to Depend on
scrollkeeper.
3. Update debhelper's dh_scrollkeeper not to edit maintainer
scripts. One of dh_scrollkeeper or lintian should be changed to
issue a warning for packages with scrollkeeper (>= 3.8) in the
Depends control file line.
4. Remove the spurious dependencies on scrollkeeper, at our leisure.
As a bonus, after this is complete it will be possible to remove
scrollkeeper while keeping all of the documentation-supplying
gnome packages installed.
5. If there are any packages which do by hand what dh_scrollkeeper
does, change them not to call scrollkeeper-update and drop
their dependency on scrollkeeper.
This is not 100% in keeping with the full transition plan defined
below: if a new gnome package is used with an old scrollkeeper, there
is some possibility that the help will not properly be available.
Unfortunately, dh_scrollkeeper doesn't generate the scrollkeeper
dependency in the control file, which makes it excessively hard to get
the dependency up to date. The bad consequences of the inaccurate
dependencies are less severe than the contortions which would be
required to deal with the problem.
TRANSITION PLAN
===============
Old dpkg to new dpkg
--------------------
The first time a trigger-supporting dpkg is run on any system, it will
activate all triggers in which anyone is interested, immediately.
These trigger activations will not be processed in the same dpkg run,
to avoid unexpectedly processing triggers while attempting an
unrelated operation. dpkg --configure --pending (and not other dpkg
operations) will run the triggers, and the dpkg postinst will warn the
user about the need to run it (if this deferred triggers condition
exists). (Any triggers activated or reactivated *after* this
mass-activation will be processed in the normal way.)
To use this correctly:
* Packages which are interested in triggers, or which want to
explicitly activate triggers, should Depend on the
triggers-supporting version of dpkg.
* Update instructions and tools should arrange to run
dpkg --configure --pending
after the install; this will process the pending triggers.
dpkg's prerm will check for attempts to downgrade while triggers are
pending and refuse. (Since the new dpkg would be installed but then
refuse to read the status file.) In case this is necessary a separate
tool will be provided which will:
* Put all packages with any pending triggers into state
config-failed and remove the list of pending triggers.
* Remove the list of awaited triggers from every package. This
may cause packages to go from triggers-awaited to installed
which is not 100% accurate but the best that can be done.
* Remove /var/lib/dpkg/triggers (to put the situation to that which
we would have seen if the trigger-supporting dpkg had never been
installed).
Higher-level programs
---------------------
The new dpkg will declare versioned Conflicts against apt and aptitude
and other critical package management tools which will be broken by
the new Status field values. Therefore, the new higher-level tools
will have to be deployed first.
The new dpkg will declare versioned Breaks against any known
noncritical package management tools which will be broken by the new
Status field value.
Transition hints for existing packages
--------------------------------------
When a central (consumer) package defines a directory where other leaf
(producer) packages may place files and/or directories, and currently
the producer packages are required to run an «update-consumer» script
in their postinst:
1. In the relevant policy, define a trigger name which is the name of
the directory where the individual files are placed by producer
packages.
2. Update the consumer package:
* Declare an interest in the trigger.
* Edit «update-consumer» so that if it is called without --real
it does the following:
if type dpkg-trigger >/dev/null 2>&1 && \
dpkg-trigger name-of-trigger; then
exit 0
fi
If this fails to cause «update-consumer» to exit, it should do
its normal update processing. Alternatively, if it is more
convenient, «update-consumer» could be renamed and supplanted with
a wrapper script which conditionally runs the real
«update-consumer».
* In the postinst, arrange for the new triggered invocation to
run «update-consumer --real». The consumer package's postinst
will already run «update-consumer» during configuration, and this
should be retained and supplemented with the --real option (or
changed to call the real script rather than the wrapper).
3. Update the producer packages:
* In the postinst, remove the call to «update-consumer».
* Change the dependency on consumer to be versioned, specifying a
trigger-interested consumer.
This can be done at our leisure. Ideally for loosely coupled
packages this would be done only in the release after the one
containing the triggers-interested consumer, to facilitate partial
upgrades and backports.
4. After all producer packages have been updated according to step 3,
«update-consumer» has become an interface internal to the consumer
and need no longer be kept stable. If un-updated producers are
still of interest, incompatible changes to «update-consumer» imply
a versioned Breaks against the old producers.
(See also “Transition plan”, below.)
If there are several consumer packages all of which are interested in
the features provided by producer packages, the current arrangements
usually involve an additional central switchboard package (eg,
emacsen-common). In this case:
-- NOTE - this part of the transition plan is still a proof of
concept and we might yet improve on it
1. Define the trigger name.
2. Update the switchboard to have any new functionality needed by the
consumers in step 3 (2nd bullet).
3. Update the consumer packages:
* Declare an interest in the trigger.
* In the postinst, arrange for the new trigger invocation to run
the compilation/registration process. This may involve scanning
for new or removed producers, and may involve new common
functionality from the switchboard (in which case a versioned
Depends is needed).
* The old interface allowing the switchboard to run
compilation/registration should be preserved, including
calls to the switchboard to register this consumer.
4. When all consumers have been updated, update the switchboard:
* Make the registration scripts called by producers try to
activate the trigger and if that succeeds quit without
doing any work (as for bullet 2 in the simple case above).
* Versioned Breaks, against the old (pre-step-3) consumers.
5. After the switchboard has been updated, producers can be updated:
* Remove the calls to the switchboard registration/compilation
functions.
* Change the dependency on the switchboard to a versioned one,
specifying the one which Breaks old consumers. Alternatively,
it may be the case that the switchboard is no longer needed (or
not needed for this producer), in which case the dependency on
the switchboard can be removed in favour of an appropriate
versioned Breaks (probably, identical to that in the new
switchboard).
6. After all the producers have been updated, the cruft in the
consumers can go away:
* Remove the calls to the switchboard's registration system.
* Versioned Breaks against old switchboards, or versioned Depends
on new switchboards, depending on whether the switchboard is
still needed for other common functionality.
7. After all of the producers and consumers have been updated, the
cruft in the switchboard can go away:
* Remove the switchboard's registration system (but not obviously
the common functionality from step 3, discussed above).
* Versioned Breaks against pre-step-6 consumers and pre-step-5
producers.
DISCUSSION
==========
The activation of a trigger does not record details of the activating
event. For example, file triggers do not inform the package of the
filename. In the future this might be added as an additional feature,
but there are some problems with this.
Broken producer packages, and error reporting
---------------------------------------------
Often trigger processing will involve a central package registering,
compiling or generally parsing some data provided by a leaf package.
If the central package finds problems with the leaf package data it is
usually more correct for only the individual leaf package to be
recorded as not properly installed. There is not currently any way to
do this and there are no plans to provide one.
The naive approach of giving the postinst a list of the triggering
packages does not work because this information is not recorded in the
right way (it might suffer from lacunae); enhancing the bookkeeping
for this to work would be possible but it is far better simply to make
the system more idempotent. See above for the recommended approach.
INTERNALS
=========
On-disk state
-------------
A single file /var/lib/dpkg/triggers/File lists all of the filename
trigger interests in the form
/path/to/directory/or/file package
For each explicit trigger in which any package is interested,
a file /var/lib/dpkg/triggers/<name-of-trigger> is a list of
the interested packages, one per line.
These interest files are not updated to remove a package just because
a state change causes it not to be interested in any triggers any more
- they are updated when we remove or unpack.
For each package which has pending triggers, the status file contains
a Triggers-Pending field which contains the space-separated names of
the pending triggers. For each package which awaits triggers the
status file contains a Triggers-Awaited field which contains the
*package* names of the packages whose trigger processing is awaited.
See “Details - Overview table” above for the invariants which relate
Triggers-Pending, Triggers-Awaited, and Status.
During dpkg's execution, /var/lib/dpkg/triggers/Unincorp is a list of
the triggers which have been requested by dpkg-trigger but not yet
incorporated in the status file. Each line is a trigger name followed
by one or more triggering package names. The triggering package name
"-" is used to indicate one or more package(s) which did not need to
await the trigger.
/var/lib/dpkg/triggers/Lock is the fcntl lockfile for the trigger
system. Processes hang onto this lock only briefly: dpkg-trigger
to add new activations, or dpkg to incorporate activations (and
perhaps when it updates interests). Therefore this lock is always
acquired with F_GETLKW so as to serialize rather than fail on
contention.
Processing
----------
dpkg-trigger updates triggers/Unincorp, and does not read or write the
status file or take out the dpkg status lock. dpkg (and dpkg-query)
reads triggers/Unincorp after reading /var/lib/dpkg/status, and after
running a maintainer script. If the status database is opened for
writing then the data from Unincorp is moved to updates as
Triggers-Pending and Triggers-Awaited entries and corresponding Status
changes.
This means that dpkg is guaranteed to reincorporate pending trigger
information into the status file only 1. when a maintainer script has
finished, or 2. when dpkg starts up with a view to performing some
operation.
When a package is unpacked or removed, its triggers control file will
be parsed and /var/lib/dpkg/triggers/* updated accordingly.
Triggers are run as part of configuration. dpkg will try to first
configure all packages which do not depend on packages which are
awaiting triggers, and then run triggers one package at a time in the
hope of making useful progress. (This will involve a new dependtry
level in configure.c's algorithm.) The only constraint on the
ordering of postinsts is only the normal Depends constraint, so the
usual Depends cycle breaking will function properly. See “Cycle
detection” below regarding cycles in the “A triggers B” relation.
Processing - Transitional
-------------------------
The case where a triggers-supporting dpkg is run for the first time is
detected by the absence of /var/lib/dpkg/triggers/Unincorp. When the
triggers-supporting dpkg starts up without this it will set each
package's list of pending triggers equal to its interests (obviously
only for packages which are in installed or triggers-pending).
This may result in a package going from installed to
triggers-pending but it will not create the directory at this time.
Packages marked as triggers-pending in this way will not be scheduled
for trigger processing in this dpkg run.
dpkg will also at this time create /var/lib/dpkg/triggers if
necessary, triggers/File, triggers/Unincorp, and the per-trigger
package lists in /var/lib/dpkg/triggers/<trigger-name>, so that future
trigger activations will be processed properly.
Only dpkg may create /var/lib/dpkg/triggers and only when it is
holding the overall dpkg status lock.
dpkg and/or dpkg-deb will be made to reject packages containing
Triggers-Pending and Triggers-Awaited control file fields, to prevent
accidents.
Cycle detection
---------------
In addition to dependency cycles, triggers raise the possibility of
mutually triggering packages - a cycle detectable only dynamically,
which we will call a “trigger cycle”.
Trigger cycles are detected using the usual hare-and-tortoise
approach. Each time after dpkg runs a postinst for triggers, dpkg
records the set of pending triggers (ie, the set of activated <pending
package, trigger name> tuples). If the hare set is a superset of the
tortoise set, a cycle has been found.
For guaranteed termination, it would be sufficient to declare a cycle
only when the two sets are identical, but because of the requirement
to make progress we can cut this short. Formally, there is supposed
to be a complete ordering of pending trigger sets satisfying the
condition that any set of pending triggers is (strictly) greater than
all its (strict) subsets. Trigger processing is supposed to
monotonically decrease the set in this ordering. (The set elements
are <package, trigger name> tuples.)
(See “Processing” above for discussion of dependency cycles.)

81
dselect/Makefile.am Normal file
View file

@ -0,0 +1,81 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = methods po
AM_CPPFLAGS = \
-DLOCALEDIR=\"$(localedir)\" \
-DADMINDIR=\"$(admindir)\" \
-DLIBDIR=\"$(pkglibexecdir)\" \
-DLOCALLIBDIR=\"/usr/local/lib/dpkg\" \
-idirafter $(top_srcdir)/lib/compat \
-iquote $(builddir) \
-I$(top_builddir) \
-I$(top_srcdir)/lib \
# EOL
AM_CXXFLAGS = \
-fno-rtti \
-fno-exceptions \
# EOL
if HAVE_LINKER_AS_NEEDED
AM_LDFLAGS = \
-Wl,--as-needed \
# EOL
endif
bin_PROGRAMS = dselect
dselect_SOURCES = \
cxx-support.cc \
dselect.h \
dselect-curses.h \
basecmds.cc \
baselist.cc \
basetop.cc \
bindings.cc bindings.h \
curkeys.cc \
helpmsgs.cc helpmsgs.h \
main.cc \
methkeys.cc \
methlist.cc \
method.cc method.h \
methparse.cc \
pkgcmds.cc \
pkgdepcon.cc \
pkgdisplay.cc \
pkginfo.cc \
pkgkeys.cc \
pkglist.cc pkglist.h \
pkgsublist.cc \
pkgtop.cc \
# EOL
dselect_LDADD = \
$(CURSES_LIBS) \
../lib/dpkg/libdpkg.la \
$(LIBINTL) \
../lib/compat/libcompat.la \
# EOL
dist_bashcompletions_DATA = \
# EOL
EXTRA_DIST = \
keyoverride \
mkcurkeys.pl \
# EOL
CLEANFILES = \
curkeys.hpp \
curkeys.h \
# EOL
curkeys.$(OBJEXT): curkeys.h
curkeys.hpp: dselect-curses.h
$(AM_V_GEN) echo '#include "dselect-curses.h"' | \
$(CPP) -dD $(CPPFLAGS) -I$(top_builddir) -I $(srcdir) - >$@
curkeys.h: $(srcdir)/keyoverride $(srcdir)/mkcurkeys.pl curkeys.hpp
$(AM_V_GEN) $(PERL) $(srcdir)/mkcurkeys.pl $< curkeys.hpp >$@
install-data-local:
$(MKDIR_P) $(DESTDIR)$(pkgconfdir)/dselect.cfg.d

1081
dselect/Makefile.in Normal file

File diff suppressed because it is too large Load diff

327
dselect/basecmds.cc Normal file
View file

@ -0,0 +1,327 @@
/*
* dselect - Debian package maintenance user interface
* basecmds.cc - base list keyboard commands display
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <utility>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/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(min(topofscreen + list_height - 1, nitems - 1));
}
void baselist::kd_redraw() {
clearok(curscr,TRUE);
redrawall();
debug(dbg_general, "baselist[%p]::kd_redraw() done", this);
}
void baselist::kd_searchagain() {
if (!searchstring.len()) {
beep();
return;
}
dosearch();
}
bool
baselist::checksearch(varbuf &str)
{
return true;
}
bool
baselist::matchsearch(int index)
{
int lendiff, i;
const char *name;
name = itemname(index);
if (!name)
return false; /* Skip things without a name (separators). */
lendiff = strlen(name) - searchstring.len();
for (i=0; i<=lendiff; i++)
if (strncasecmp(name + i, searchstring.str(), searchstring.len()) == 0)
return true;
return false;
}
void baselist::kd_search() {
varbuf newsearchstring(128);
newsearchstring = searchstring;
werase(querywin);
mvwaddstr(querywin,0,0, _("Search for ? "));
echo();
if (wgetnstr(querywin, newsearchstring.buf, newsearchstring.size - 1) == ERR)
searchstring.reset();
newsearchstring.trunc(strlen(newsearchstring.buf));
resize_window();
noecho();
if (whatinfo_height) { touchwin(whatinfowin); refreshinfo(); }
else if (info_height) { touchwin(infopad); refreshinfo(); }
else if (thisstate_height) redrawthisstate();
else { touchwin(listpad); refreshlist(); }
if (newsearchstring.len()) {
if (!checksearch(newsearchstring)) {
beep();
return;
}
searchstring = std::move(newsearchstring);
dosearch();
} else
kd_searchagain();
}
void
baselist::displayerror(const char *str)
{
const char *pr = _("Error: ");
int prlen=strlen(pr);
beep();
werase(querywin);
mvwaddstr(querywin,0,0,pr);
mvwaddstr(querywin,0,prlen,str);
wgetch(querywin);
if (whatinfo_height) { touchwin(whatinfowin); refreshinfo(); }
else if (info_height) { touchwin(infopad); refreshinfo(); }
else if (thisstate_height) redrawthisstate();
}
void baselist::displayhelp(const struct helpmenuentry *helpmenu, int key) {
int maxx, maxy, i, nextkey;
wbkgdset(stdscr, ' ' | part_attr[helpscreen]);
clearok(stdscr,TRUE);
for (;;) {
getmaxyx(stdscr, maxy, maxx);
werase(stdscr);
const struct helpmenuentry *hme = helpmenu;
while (hme->key && hme->key != key)
hme++;
if (hme->key) {
int x, y DPKG_ATTR_UNUSED;
attrset(part_attr[helpscreen]);
mvaddstr(1,0, gettext(hme->msg->text));
attrset(part_attr[title]);
mvaddstr(0,0, _("Help: "));
addstr(gettext(hme->msg->title));
getyx(stdscr,y,x);
while (++x<maxx) addch(' ');
attrset(part_attr[thisstate]);
mvaddstr(maxy-1,0,
_("Press ? for help menu, . for next topic, <space> to exit help."));
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, gettext(hme->msg->title));
}
mvaddstr(i+4,1,
_("Press a key from the list above, <space> or 'q' to exit help,\n"
" or '.' (full stop) to read each help page in turn. "));
nextkey= helpmenu[0].key;
}
refresh();
do {
int curkey = key;
key = getch();
if (key == KEY_RESIZE) {
resize_window();
key = curkey;
}
} while (key == ERR && errno == EINTR);
if (key == EOF) ohshite(_("error reading keyboard in help"));
if (key == ' ' || key == 'q') {
break;
} else if (key == '?' || key == 'h') {
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();
}

412
dselect/baselist.cc Normal file
View file

@ -0,0 +1,412 @@
/*
* dselect - Debian package maintenance user interface
* baselist.cc - list of somethings
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
* Copyright © 2007-2013 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/c-ctype.h>
#include <dpkg/dpkg.h>
#include <dpkg/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);
}
void
baselist::resize_window()
{
debug(dbg_general, "baselist::resize_window(), baselist=%p", this);
enddisplay();
startdisplay();
if (doupdate() == ERR)
ohshite(_("cannot update screen after window resize"));
}
void
baselist::add_column(column &col, const char *title, int width)
{
col.title = title;
col.x = col_cur_x;
col.width = width;
col_cur_x += col.width + gap_width;
}
void
baselist::end_column(column &col, const char *title)
{
col.title = title;
col.x = col_cur_x;
col.width = total_width - col.x;
col_cur_x += col.width + gap_width;
}
void
baselist::draw_column_head(const column &col)
{
mvwaddnstr(colheadspad, 0, col.x, col.title, col.width);
}
void
baselist::draw_column_sep(const column &col, int y)
{
mvwaddch(listpad, y, col.x - 1, ' ');
}
void
baselist::draw_column_item(const column &col, int y, const char *item)
{
mvwprintw(listpad, y, col.x, "%-*.*s", col.width, col.width, item);
}
void baselist::setheights() {
int y= ymax - (title_height + colheads_height + thisstate_height);
if (y < 1)
internerr("widget y=%d < 1", y);
if (showinfo==2 && y>=7) {
list_height= 5;
whatinfo_height= 1;
info_height= y-6;
} else if (showinfo==1 && y>=10) {
list_height= y/2;
info_height= (y-1)/2;
whatinfo_height= 1;
} else {
list_height= y;
info_height= 0;
whatinfo_height= 0;
}
colheads_row= title_height;
list_row= colheads_row + colheads_height;
thisstate_row= list_row + list_height;
info_row= thisstate_row + thisstate_height;
whatinfo_row= ymax - 1;
}
void baselist::startdisplay() {
debug(dbg_general, "baselist[%p]::startdisplay()", this);
cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
clear(); wnoutrefresh(stdscr);
// find attributes
if (has_colors() && start_color()==OK && COLOR_PAIRS >= numscreenparts) {
int i;
printf("allocing\n");
for (i = 1; i < numscreenparts; i++) {
if (init_pair(i, color[i].fore, color[i].back) != OK)
ohshite(_("cannot allocate color pair"));
part_attr[i] = COLOR_PAIR(i) | color[i].attr;
}
} else {
/* User defined attributes for B&W mode are not currently supported. */
part_attr[title] = A_REVERSE;
part_attr[thisstate] = A_STANDOUT;
part_attr[list] = 0;
part_attr[listsel] = A_STANDOUT;
part_attr[selstate] = A_BOLD;
part_attr[selstatesel] = A_STANDOUT;
part_attr[colheads]= A_BOLD;
part_attr[query] = part_attr[title];
part_attr[info_body] = part_attr[list];
part_attr[info_head] = A_BOLD;
part_attr[whatinfo] = part_attr[thisstate];
part_attr[helpscreen] = A_NORMAL;
}
// set up windows and pads, based on screen size
getmaxyx(stdscr,ymax,xmax);
title_height= ymax>=6;
colheads_height= ymax>=5;
thisstate_height= ymax>=3;
setheights();
setwidths();
titlewin= newwin(1,xmax, 0,0);
if (!titlewin) ohshite(_("failed to create title window"));
wattrset(titlewin, part_attr[title]);
whatinfowin= newwin(1,xmax, whatinfo_row,0);
if (!whatinfowin) ohshite(_("failed to create whatinfo window"));
wattrset(whatinfowin, part_attr[whatinfo]);
listpad = newpad(ymax, 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, part_attr[colheads]);
thisstatepad= newpad(1, total_width);
if (!thisstatepad) ohshite(_("failed to create thisstate pad"));
wattrset(thisstatepad, part_attr[thisstate]);
infopad= newpad(MAX_DISPLAY_INFO, total_width);
if (!infopad) ohshite(_("failed to create info pad"));
wattrset(infopad, part_attr[info_body]);
wbkgdset(infopad, ' ' | part_attr[info_body]);
querywin= newwin(1,xmax,ymax-1,0);
if (!querywin) ohshite(_("failed to create query window"));
wbkgdset(querywin, ' ' | part_attr[query]);
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();
debug(dbg_general,
"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 = nullptr;
col_cur_x = 0;
}
void baselist::redrawall() {
redrawtitle();
redrawcolheads();
wattrset(listpad, part_attr[list]);
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) {
debug(dbg_general, "baselist[%p]::baselist()", this);
bindings= kb;
nitems= 0;
col_cur_x = 0;
gap_width = 1;
total_width = max(TOTAL_LIST_WIDTH, COLS);
xmax= -1;
ymax = -1;
list_height = 0;
info_height = 0;
title_height = 0;
whatinfo_height = 0;
colheads_height = 0;
thisstate_height = 0;
list_row = 0;
info_row = 0;
whatinfo_row = 0;
colheads_row = 0;
thisstate_row = 0;
topofscreen = 0;
leftofscreen = 0;
infotopofscreen = 0;
infolines = 0;
listpad = nullptr;
infopad = nullptr;
colheadspad = nullptr;
thisstatepad = nullptr;
titlewin = nullptr;
querywin = nullptr;
whatinfowin = nullptr;
cursorline = -1;
ldrawnstart = 0;
ldrawnend = 0;
showinfo= 1;
searchstring.reset();
}
void baselist::itd_keys() {
whatinfovb += _("Keybindings");
const int givek= xmax/3;
bindings->describestart();
const char **ta;
while ((ta = bindings->describenext()) != nullptr) {
const char **tap= ta+1;
for (;;) {
waddstr(infopad, gettext(*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');
delete [] ta;
}
}
void baselist::dosearch() {
int offset, index;
debug(dbg_general, "baselist[%p]::dosearch(); searchstring='%s'",
this, searchstring.str());
for (offset = 1, index = max(topofscreen, cursorline + 1);
offset<nitems;
offset++, index++) {
if (index >= nitems) index -= nitems;
if (matchsearch(index)) {
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,
min(info_row + info_height - 1, info_row + MAX_DISPLAY_INFO - 1),
min(total_width - leftofscreen - 1, xmax - 1));
if (whatinfo_height) {
mywerase(whatinfowin);
mvwaddstr(whatinfowin,0,0, whatinfovb.str());
if (infolines > info_height) {
wprintw(whatinfowin,_(" -- %d%%, press "),
(infotopofscreen + info_height) * 100 / infolines);
if (infotopofscreen + info_height < infolines) {
wprintw(whatinfowin, _("%s for more"), bindings->find("iscrollon").str());
if (infotopofscreen) waddstr(whatinfowin, ", ");
}
if (infotopofscreen)
wprintw(whatinfowin, _("%s to go back"), bindings->find("iscrollback").str());
waddch(whatinfowin,'.');
}
wnoutrefresh(whatinfowin);
}
}
void baselist::wordwrapinfo(int offset, const char *m) {
ssize_t usemax = xmax - 5;
debug(dbg_general, "baselist[%p]::wordwrapinfo(%d, '%s')", this, offset, m);
bool wrapping = false;
for (;;) {
int offleft=offset; while (*m == ' ' && offleft>0) { m++; offleft--; }
const char *p = strchrnul(m, '\n');
ptrdiff_t l = p - m;
while (l && c_isspace(m[l - 1]))
l--;
if (!l || (*m == '.' && l == 1)) {
if (wrapping) waddch(infopad,'\n');
waddch(infopad, '\n');
wrapping = false;
} else if (*m == ' ' || usemax < 10) {
if (wrapping) waddch(infopad,'\n');
waddnstr(infopad, m, l);
waddch(infopad, '\n');
wrapping = false;
} else {
int x, y DPKG_ATTR_UNUSED;
if (wrapping) {
getyx(infopad, y,x);
if (x+1 >= usemax) {
waddch(infopad,'\n');
} else {
waddch(infopad,' ');
}
}
for (;;) {
getyx(infopad, y,x);
ssize_t dosend = usemax - x;
if (l <= dosend) {
dosend=l;
} else {
ssize_t 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 = true;
}
if (*p == '\0')
break;
if (getcury(infopad) == (MAX_DISPLAY_INFO - 1)) {
waddstr(infopad,
"[The package description is too long and has been truncated...]");
break;
}
m= ++p;
}
debug(dbg_general, "baselist[%p]::wordwrapinfo() done", this);
}
baselist::~baselist() { }

52
dselect/basetop.cc Normal file
View file

@ -0,0 +1,52 @@
/*
* dselect - Debian package maintenance user interface
* basetop.cc - base list class redraw of top
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
void baselist::refreshlist() {
redrawitemsrange(topofscreen, min(nitems, topofscreen + list_height));
int y, x, maxy, maxx;
y = min(list_row + list_height - 1, list_row + nitems - topofscreen - 1);
x = min(total_width - leftofscreen - 1, xmax - 1);
pnoutrefresh(listpad, 0, 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) {
int i;
for (i = start; i < end; i++) {
redraw1item(i);
}
}
void baselist::refreshcolheads() {
pnoutrefresh(colheadspad, 0,leftofscreen, colheads_row,0,
colheads_row, min(total_width - leftofscreen - 1, xmax - 1));
}

184
dselect/bindings.cc Normal file
View file

@ -0,0 +1,184 @@
/*
* dselect - Debian package maintenance user interface
* bindings.cc - keybinding manager object definitions and default bindings
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <string.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
#include "bindings.h"
keybindings::keybindings(const interpretation *ints, const orgbinding *orgbindings) {
interps= ints;
bindings = nullptr;
const orgbinding *b= orgbindings;
while (b->action) { bind(b->key,b->action); b++; }
describestart();
}
bool
keybindings::bind(int key, const char *action)
{
if (key == -1)
return false;
const interpretation *interp = interps;
while (interp->action && strcmp(interp->action, action))
interp++;
if (!interp->action)
return false;
const description *desc = descriptions;
while (desc->action && strcmp(desc->action, action))
desc++;
binding *b = bindings;
while (b && b->key != key)
b = b->next;
if (!b) {
b = new binding;
b->key = key;
b->next = bindings;
bindings = b;
}
b->interp = interp;
b->desc = desc->desc;
return true;
}
varbuf
keybindings::find(const char *action) {
binding *b = bindings;
while (b && strcmp(action, b->interp->action))
b = b->next;
if (!b)
return varbuf(_("[not bound]"));
const char *n= key2name(b->key);
if (n)
return varbuf(n);
varbuf unknown;
unknown.set_fmt(_("[unk: %d]"), b->key);
return unknown;
}
const keybindings::interpretation *keybindings::operator()(int key) {
binding *b = bindings;
while (b && b->key != key)
b = b->next;
if (!b)
return nullptr;
return b->interp;
}
const char **keybindings::describenext() {
binding *search;
int count;
for (;;) {
if (!iterate->action)
return nullptr;
for (count=0, search=bindings; search; search=search->next)
if (strcmp(search->interp->action, iterate->action) == 0)
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) == 0)
retarray[count++]= key2name(search->key);
retarray[count] = nullptr;
iterate++;
return retarray;
}
const char *keybindings::key2name(int key) {
const keyname *search = keynames;
while (search->key != -1 && search->key != key)
search++;
return search->kname;
}
int keybindings::name2key(const char *name) {
const keyname *search = keynames;
while (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", N_("Scroll onwards through help/information") },
{ "iscrollback", N_("Scroll backwards through help/information") },
{ "up", N_("Move up") },
{ "down", N_("Move down") },
{ "top", N_("Go to top of list") },
{ "bottom", N_("Go to end of list") },
{ "help", N_("Request help (cycle through help screens)") },
{ "info", N_("Cycle through information displays") },
{ "redraw", N_("Redraw display") },
{ "scrollon1", N_("Scroll onwards through list by 1 line") },
{ "scrollback1", N_("Scroll backwards through list by 1 line") },
{ "iscrollon1", N_("Scroll onwards through help/information by 1 line") },
{ "iscrollback1", N_("Scroll backwards through help/information by 1 line") },
{ "scrollon", N_("Scroll onwards through list") },
{ "scrollback", N_("Scroll backwards through list") },
// Actions which apply only to lists of packages.
{ "install", N_("Mark package(s) for installation") },
{ "remove", N_("Mark package(s) for deinstallation") },
{ "purge", N_("Mark package(s) for deinstall and purge") },
{ "morespecific", N_("Make highlight more specific") },
{ "lessspecific", N_("Make highlight less specific") },
{ "search", N_("Search for a package whose name contains a string") },
{ "searchagain", N_("Repeat last search") },
{ "swaporder", N_("Swap sort order priority/section") },
{ "quitcheck", N_("Quit, confirming, and checking dependencies") },
{ "quitnocheck", N_("Quit, confirming without check") },
{ "quitrejectsug", N_("Quit, rejecting conflict/dependency suggestions") },
{ "abortnocheck", N_("Abort - quit without making changes") },
{ "revert", N_("Revert to old state for all packages") },
{ "revertsuggest", N_("Revert to suggested state for all packages") },
{ "revertdirect", N_("Revert to directly requested state for all packages") },
{ "revertinstalled", N_("Revert to currently installed state for all packages") },
// Actions which apply only to lists of methods.
{ "select-and-quit", N_("Select currently-highlighted access method") },
{ "abort", N_("Quit without changing selected access method") },
{ nullptr, nullptr }
};

96
dselect/bindings.h Normal file
View file

@ -0,0 +1,96 @@
/*
* dselect - Debian package maintenance user interface
* bindings.h - keybindings class header file
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BINDINGS_H
#define BINDINGS_H
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;
bool bind(int key, const char *action);
public:
int name2key(const char *name);
const char *key2name(int key);
bool bind(const char *name, const char *action)
{ return bind(name2key(name), action); }
const interpretation *operator()(int key);
varbuf 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[];
#ifndef CTRL
#define CTRL(x) ((x) - 'a' + 1)
#endif
#endif /* BINDINGS_H */

31
dselect/curkeys.cc Normal file
View file

@ -0,0 +1,31 @@
/*
* dselect - Debian package maintenance user interface
* curkeys.cc - list of ncurses keys for name <-> key mapping
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
#include "bindings.h"
const keybindings::keyname keybindings::keynames[] = {
#include "curkeys.h"
};

82
dselect/cxx-support.cc Normal file
View file

@ -0,0 +1,82 @@
/*
* dselect - Debian package maintenance user interface
* cxx-support.cc - C++ support code for dselect
*
* Copyright © 1994-1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <sys/types.h>
#include <stdlib.h>
#ifdef HAVE_CXXABI_H
#include <cxxabi.h>
#endif
#include <new>
#include <dpkg/dpkg.h>
extern void *
operator new(size_t size) DPKG_ATTR_THROW(std::bad_alloc)
{
return m_malloc(size);
}
extern void *
operator new[](size_t size) DPKG_ATTR_THROW(std::bad_alloc)
{
return m_malloc(size);
}
extern void
operator delete(void *p) DPKG_ATTR_NOEXCEPT
{
free(p);
}
extern void
operator delete(void *p, size_t size) DPKG_ATTR_NOEXCEPT
{
free(p);
}
extern void
operator delete[](void *a) DPKG_ATTR_NOEXCEPT
{
free(a);
}
extern void
operator delete[](void *a, size_t size) DPKG_ATTR_NOEXCEPT
{
free(a);
}
#ifdef HAVE___CXA_PURE_VIRTUAL
namespace __cxxabiv1 {
extern "C" void
__cxa_pure_virtual()
{
internerr("pure virtual function called");
}
}
#endif

38
dselect/dselect-curses.h Normal file
View file

@ -0,0 +1,38 @@
/*
* dselect - Debian package maintenance user interface
* dselect-curses.h - curses header wrapper
*
* Copyright © 2009 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef DSELECT_CURSES_H
#define DSELECT_CURSES_H
#include <config.h>
#undef ERR
#if defined(HAVE_NCURSESW_NCURSES_H)
#include <ncursesw/ncurses.h>
#elif defined(HAVE_NCURSES_NCURSES_H)
#include <ncurses/ncurses.h>
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#else
#include <curses.h>
#endif
#endif /* DSELECT_CURSES_H */

204
dselect/dselect.h Normal file
View file

@ -0,0 +1,204 @@
/*
* dselect - Debian package maintenance user interface
* dselect.h - external definitions for this program
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef DSELECT_H
#define DSELECT_H
#include <signal.h>
#include <algorithm>
using std::min;
using std::max;
#include <dpkg/debug.h>
#include "dselect-curses.h"
#define DSELECT "dselect"
#define TOTAL_LIST_WIDTH 180
#define MAX_DISPLAY_INFO 120
struct helpmenuentry {
char key;
const struct helpmessage *msg;
};
struct keybindings;
enum screenparts {
background,
list,
listsel,
title,
thisstate,
selstate,
selstatesel,
colheads,
query,
info_body,
info_head,
whatinfo,
helpscreen,
numscreenparts,
};
struct column {
column(): title(nullptr), x(0), width(0) {}
void blank() { title = nullptr; x = 0; width = 0; }
const char *title;
int x;
int width;
};
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 part_attr[numscreenparts];
int gap_width;
int col_cur_x;
int total_width;
void add_column(column &col, const char *title, int width);
void end_column(column &col, const char *title);
void draw_column_head(const column &col);
void draw_column_sep(const column &col, int y);
void draw_column_item(const column &col, int y, const char *item);
// (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.
// Window resize handling (via SIGWINCH).
void resize_window();
int nitems, ldrawnstart, ldrawnend, showinfo;
int topofscreen, leftofscreen, cursorline;
int infotopofscreen, infolines;
varbuf whatinfovb;
varbuf searchstring;
virtual void setheights();
void unsizes();
void dosearch();
void displayhelp(const struct helpmenuentry *menu, int key);
void displayerror(const char *str);
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;
virtual bool checksearch(varbuf &str);
virtual bool matchsearch(int index);
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();
explicit baselist(keybindings *);
virtual ~baselist();
};
void displayhelp(const struct helpmenuentry *menu, int key);
void mywerase(WINDOW *win);
void curseson();
void cursesoff();
extern bool expertmode;
struct colordata {
int fore;
int back;
int attr;
};
extern colordata color[];
/* Evil recommends flag variable. */
extern bool manual_install;
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;
#endif /* DSELECT_H */

217
dselect/helpmsgs.cc Normal file
View file

@ -0,0 +1,217 @@
/*
* dselect - Debian package maintenance user interface
* helpmsgs.cc - list of help messages
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <dpkg/i18n.h>
#include "helpmsgs.h"
const struct helpmessage hlp_listkeys = {
N_("Keystrokes"), N_("\
Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:\n\
j, Down-arrow k, Up-arrow move highlight\n\
N, Page-down, Space P, Page-up, Backspace scroll list by 1 page\n\
^n ^p scroll list by 1 line\n\
t, Home e, End jump to top/end of list\n\
u d scroll info by 1 page\n\
^u ^d scroll info by 1 line\n\
B, Left-arrow F, Right-arrow pan display by 1/3 screen\n\
^b ^f pan display by 1 character\n\n\
\
Mark packages for later processing:\n\
+, Insert install or upgrade =, H hold in present version\n\
-, Delete remove :, G unhold: upgrade or leave uninstalled\n\
_ remove & purge config\n\
Miscellaneous:\n\
Quit, exit, overwrite (note capitals!): ?, F1 request help (also Help)\n\
Return Confirm, quit (check dependencies) i, I toggle/cycle info displays\n\
Q Confirm, quit (override dep.s) o, O cycle through sort options\n\
X, Esc eXit, abandoning any changes made v, A, V change status display opts\n\
R Revert to state before this list ^l redraw display\n\
U set all to sUggested state / search (Return to cancel)\n\
D set all to Directly requested state n, \\ repeat last search\n")
};
const struct helpmessage hlp_mainintro = {
N_("Introduction to package selections"), N_("\
Welcome to dselect's main package listing.\n\n\
\
You will be presented with a list of packages which are installed or available\n\
for installation. You can navigate around the list using the cursor keys,\n\
mark packages for installation (using '+') or deinstallation (using '-').\n\
Packages can be marked either singly or in groups; initially you will see that\n\
the line 'All packages' is selected. '+', '-' and so on will affect all the\n\
packages described by the highlighted line.\n\n\
\
Some of your choices will cause conflicts or dependency problems; you will be\n\
given a sub-list of the relevant packages, so that you can solve the problems.\n\n\
\
You should read the list of keys and the explanations of the display.\n\
Much on-line help is available, please make use of it - press '?' at\n\
any time for help.\n\n\
\
When you have finished selecting packages, press <enter> to confirm changes,\n\
or 'X' to quit without saving changes. A final check on conflicts and\n\
dependencies will be done - here too you may see a sublist.\n\n\
\
Press <space> to leave help and enter the list now.\n")
};
const struct helpmessage hlp_readonlyintro = {
N_("Introduction to read-only package list browser"), N_("\
Welcome to dselect's main package listing.\n\n\
\
You will be presented with a list of packages which are installed or available\n\
for installation. Since you do not have the privilege necessary to update\n\
package states, you are in a read-only mode. You can navigate around the\n\
list using the cursor keys (please see the 'Keystrokes' help screen), observe\n\
the status of the packages and read information about them.\n\n\
\
You should read the list of keys and the explanations of the display.\n\
Much on-line help is available, please make use of it - press '?' at\n\
any time for help.\n\n\
\
When you have finished browsing, press 'Q' or <enter> to quit.\n\n\
\
Press <space> to leave help and enter the list now.\n")
};
const struct helpmessage hlp_recurintro = {
N_("Introduction to conflict/dependency resolution sub-list"), N_("\
Dependency/conflict resolution - introduction.\n\n\
\
One or more of your choices have raised a conflict or dependency problem -\n\
some packages should only be installed in conjunction with certain others, and\n\
some combinations of packages may not be installed together.\n\n\
\
You will see a sub-list containing the packages involved. The bottom half of\n\
the display shows relevant conflicts and dependencies; use 'i' to cycle between\n\
that, the package descriptions and the internal control information.\n\n\
\
A set of 'suggested' packages has been calculated, and the initial markings in\n\
this sub-list have been set to match those, so you can just hit Return to\n\
accept the suggestions if you wish. You may abort the change(s) which caused\n\
the problem(s), and go back to the main list, by pressing capital 'X'.\n\n\
\
You can also move around the list and change the markings so that they are more\n\
like what you want, and you can 'reject' my suggestions by using the capital\n\
'D' or 'R' keys (see the keybindings help screen). You can use capital 'Q' to\n\
force to accept the situation currently displayed, in case you want to\n\
override a recommendation or think that the program is mistaken.\n\n\
\
Press <space> to leave help and enter the sub-list; remember: press '?' for help.\n")
};
const struct helpmessage hlp_displayexplain1 = {
N_("Display, part 1: package listing and status chars"), N_("\
The top half of the screen shows a list of packages. For each package you see\n\
four columns for its current status on the system and mark. In terse mode (use\n\
'v' to toggle verbose display) these are single characters, from left to right:\n\n\
\
Error flag: Space - no error (but package may be in broken state - see below)\n\
'R' - serious error during installation, needs reinstallation;\n\
Installed state: Space - not installed;\n\
'*' - installed;\n\
'-' - not installed but config files remain;\n\
packages in these { 'U' - unpacked but not yet configured;\n\
states are not { 'C' - half-configured (an error happened);\n\
(quite) properly { 'I' - half-installed (an error happened);\n\
installed { 'W','t' - triggers are awaited resp. pending.\n\
Old mark: what was requested for this package before presenting this list;\n\
Mark: what is requested for this package:\n\
'*': marked for installation or upgrade;\n\
'-': marked for removal, but any configuration files will remain;\n\
'=': on hold: package will not be installed, upgraded or removed;\n\
'_': marked for purge completely - even remove configuration;\n\
'n': package is new and has yet to be marked for install/remove/&c.\n\n\
\
Also displayed are each package's Priority, Section, name, installed and\n\
available version numbers (shift-V to display/hide) and summary description.\n")
};
const struct helpmessage hlp_displayexplain2 = {
N_("Display, part 2: list highlight; information display"), N_("\
* Highlight: One line in the package list will be highlighted. It indicates\n\
which package(s) will be affected by presses of '+', '-' and '_'.\n\n\
\
* The dividing line in the middle of the screen shows a brief explanation of\n\
the status of the currently-highlighted package, or a description of which\n\
group is highlighted if a group line is. If you don't understand the\n\
meaning of some of the status characters displayed, go to the relevant\n\
package and look at this divider line, or use the 'v' key for a verbose\n\
display (press 'v' again to go back to the terse display).\n\n\
\
* The bottom of the screen shows more information about the\n\
currently-highlighted package (if there is only one).\n\n\
\
It can show an extended description of the package, the internal package\n\
control details (either for the installed or available version of the\n\
package), or information about conflicts and dependencies involving the\n\
current package (in conflict/dependency resolution sublists).\n\n\
\
Use the 'i' key to cycle through the displays, and 'I' to hide the\n\
information display or expand it to use almost all of the screen.\n")
};
const struct helpmessage hlp_methintro = {
N_("Introduction to method selection display"), N_("\
dselect and dpkg can do automatic installation, loading the package files to be\n\
installed from one of a number of different possible places.\n\n\
\
This list allows you to select one of these installation methods.\n\n\
\
Move the highlight to the method you wish to use, and hit Enter. You will then\n\
be prompted for the information required to do the installation.\n\n\
\
As you move the highlight a description of each method, where available, is\n\
displayed in the bottom half of the screen.\n\n\
\
If you wish to quit without changing anything use the 'x' key while in the list\n\
of installation methods.\n\n\
\
A full list of keystrokes is available by pressing 'k' now, or from the help\n\
menu reachable by pressing '?'.\n")
};
const struct helpmessage hlp_methkeys = {
N_("Keystrokes for method selection"), N_("\
Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:\n\
j, Down-arrow k, Up-arrow move highlight\n\
N, Page-down, Space P, Page-up, Backspace scroll list by 1 page\n\
^n ^p scroll list by 1 line\n\
t, Home e, End jump to top/end of list\n\
u d scroll info by 1 page\n\
^u ^d scroll info by 1 line\n\
B, Left-arrow F, Right-arrow pan display by 1/3 screen\n\
^b ^f pan display by 1 character\n\
(These are the same motion keys as in the package list display.)\n\n\
\
Quit:\n\
Return, Enter select this method and go to its configuration dialogue\n\
x, X exit without changing or setting up the installation method\n\n\
\
Miscellaneous:\n\
?, Help, F1 request help\n\
^l redraw display\n\
/ search (just return to cancel)\n\
\\ repeat last search\n")
};

38
dselect/helpmsgs.h Normal file
View file

@ -0,0 +1,38 @@
/*
* dselect - Debian package maintenance user interface
* helpmsgs.h - external definitions for the list of help messages
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HELPMSGS_H
#define HELPMSGS_H
struct helpmessage {
const char *title;
const char *text;
};
extern const struct helpmessage hlp_listkeys;
extern const struct helpmessage hlp_mainintro;
extern const struct helpmessage hlp_readonlyintro;
extern const struct helpmessage hlp_recurintro;
extern const struct helpmessage hlp_displayexplain1;
extern const struct helpmessage hlp_displayexplain2;
extern const struct helpmessage hlp_methintro;
extern const struct helpmessage hlp_methkeys;
#endif /* HELPMSGS_H */

58
dselect/keyoverride Normal file
View file

@ -0,0 +1,58 @@
# dselect - Debian package maintenance user interface
# keyoverride - override strings for ncurses key names
#
# Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
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]

567
dselect/main.cc Normal file
View file

@ -0,0 +1,567 @@
/*
* dselect - Debian package maintenance user interface
* main.cc - main program
*
* Copyright © 1994-1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
* Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
// Solaris requires curses.h to be included before term.h
#include "dselect-curses.h"
#if defined(HAVE_NCURSESW_TERM_H)
#include <ncursesw/term.h>
#elif defined(HAVE_NCURSES_TERM_H)
#include <ncurses/term.h>
#else
#include <term.h>
#endif
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/options.h>
#include <dpkg/fsys.h>
#include "dselect.h"
#include "bindings.h"
#include "pkglist.h"
static const char printforhelp[] = N_("Type dselect --help for help.");
bool expertmode = false;
static keybindings packagelistbindings(packagelist_kinterps,packagelist_korgbindings);
struct table_t {
const char *name;
const int num;
};
static const struct table_t colortable[] = {
{"black", COLOR_BLACK },
{"red", COLOR_RED },
{"green", COLOR_GREEN },
{"yellow", COLOR_YELLOW },
{"blue", COLOR_BLUE },
{"magenta", COLOR_MAGENTA },
{"cyan", COLOR_CYAN },
{"white", COLOR_WHITE },
{nullptr, 0},
};
static const struct table_t attrtable[]= {
{"normal", A_NORMAL },
{"standout", A_STANDOUT },
{"underline", A_UNDERLINE },
{"reverse", A_REVERSE },
{"blink", A_BLINK },
{"bright", A_BLINK }, // on some terminals
{"dim", A_DIM },
{"bold", A_BOLD },
{nullptr, 0},
};
/* A slightly confusing mapping from dselect's internal names to
* the user-visible names.*/
static const struct table_t screenparttable[]= {
{"list", list },
{"listsel", listsel },
{"title", title },
{"infohead", thisstate },
{"pkgstate", selstate },
{"pkgstatesel", selstatesel },
{"listhead", colheads },
{"query", query },
{"info", info_body },
{"infodesc", info_head },
{"infofoot", whatinfo },
{"helpscreen", helpscreen },
{nullptr, 0},
};
/* Original colors. */
struct colordata color[]= {
/* fore back attr */
{COLOR_WHITE, COLOR_BLACK, 0 }, // default, not used
{COLOR_WHITE, COLOR_BLACK, 0 }, // list
{COLOR_WHITE, COLOR_BLACK, A_REVERSE }, // listsel
{COLOR_WHITE, COLOR_RED, 0 }, // title
{COLOR_WHITE, COLOR_BLUE, 0 }, // thisstate
{COLOR_WHITE, COLOR_BLACK, A_BOLD }, // selstate
{COLOR_WHITE, COLOR_BLACK, A_REVERSE | A_BOLD }, // selstatesel
{COLOR_WHITE, COLOR_BLUE, 0 }, // colheads
{COLOR_WHITE, COLOR_RED, 0 }, // query
{COLOR_WHITE, COLOR_BLACK, 0 }, // info_body
{COLOR_WHITE, COLOR_BLACK, A_BOLD }, // info_head
{COLOR_WHITE, COLOR_BLUE, 0 }, // whatinfo
{COLOR_WHITE, COLOR_BLACK, 0 }, // help
};
struct menuentry {
const char *command;
const char *key;
const char *option;
const char *menuent;
urqfunction *fn;
};
static const menuentry menuentries[]= {
{ "access", N_("a"), N_("[A]ccess"), N_("Choose the access method to use."), &urq_setup },
{ "update", N_("u"), N_("[U]pdate"), N_("Update list of available packages, if possible."), &urq_update },
{ "select", N_("s"), N_("[S]elect"), N_("Request which packages you want on your system."), &urq_list },
{ "install", N_("i"), N_("[I]nstall"),N_("Install and upgrade wanted packages."), &urq_install },
{ "config", N_("c"), N_("[C]onfig"), N_("Configure any packages that are unconfigured."), &urq_config },
{ "remove", N_("r"), N_("[R]emove"), N_("Remove unwanted software."), &urq_remove },
{ "quit", N_("q"), N_("[Q]uit"), N_("Quit dselect."), &urq_quit },
{ nullptr, nullptr, N_("menu"), nullptr, &urq_menu },
{ nullptr }
};
static const char programdesc[]=
N_("Debian '%s' package handling frontend version %s.\n");
static const char licensestring[]= N_(
"This is free software; see the GNU General Public License version 2 or\n"
"later for copying conditions. There is NO warranty.\n");
static void DPKG_ATTR_NORET
printversion(const struct cmdinfo *ci, const char *value)
{
printf(gettext(programdesc), DSELECT, PACKAGE_RELEASE);
printf("%s", gettext(licensestring));
m_output(stdout, _("<standard output>"));
exit(0);
}
static void DPKG_ATTR_NORET
usage(const struct cmdinfo *ci, const char *value)
{
int i;
printf(_(
"Usage: %s [<option>...] [<command>...]\n"
"\n"), DSELECT);
printf(_("Commands:\n"));
for (i = 0; menuentries[i].command; i++)
printf(" %-10s %s\n", menuentries[i].command, menuentries[i].menuent);
fputs("\n", stdout);
printf(_(
"Options:\n"
" --admindir <directory> Use <directory> instead of %s.\n"
" --instdir <directory> Use <directory> instead of %s.\n"
" --root <directory> Use <directory> instead of %s.\n"
" --expert Turn on expert mode.\n"
" -D, --debug <file> Turn on debugging, send output to <file>.\n"
" --color <color-spec> Configure screen colors.\n"
" --colour <color-spec> Ditto.\n"
), ADMINDIR, "/", "/");
printf(_(
" -?, --help Show this help message.\n"
" --version Show the version.\n"
"\n"));
printf(_("<color-spec> is <screen-part>:[<foreground>],[<background>][:<attr>[+<attr>]...]\n"));
printf(_("<screen-part> is:"));
for (i=0; screenparttable[i].name; i++)
printf(" %s", screenparttable[i].name);
fputs("\n", stdout);
printf(_("<color> is:"));
for (i = 0; colortable[i].name; i++)
printf(" %s", colortable[i].name);
fputs("\n", stdout);
printf(_("<attr> is:"));
for (i=0; attrtable[i].name; i++)
printf(" %s", attrtable[i].name);
fputs("\n", stdout);
m_output(stdout, _("<standard output>"));
exit(0);
}
/* These are called by C code, so need to have C calling convention */
extern "C" {
static void
set_debug(const struct cmdinfo*, const char *v)
{
FILE *fp;
fp = fopen(v, "a");
if (!fp)
ohshite(_("couldn't open debug file '%.255s'\n"), v);
debug_set_output(fp, v);
debug_set_mask(dbg_general | dbg_depcon);
}
static void
set_expert(const struct cmdinfo*, const char *v)
{
expertmode = true;
}
static int
findintable(const struct table_t *table, const char *item, const char *tablename)
{
int i;
for (i = 0; item && (table[i].name != nullptr); i++)
if (strcasecmp(item, table[i].name) == 0)
return table[i].num;
ohshit(_("invalid %s '%s'"), tablename, item);
}
/*
* The string's format is:
* screenpart:[forecolor][,backcolor][:[<attr>, ...]
* Examples: --color title:black,cyan:bright+underline
* --color list:red,yellow
* --color colheads:,green:bright
* --color selstate::reverse // doesn't work FIXME
*/
static void
set_color(const struct cmdinfo*, const char *string)
{
char *s;
char *colors, *attributes;
int screenpart;
s = m_strdup(string); // strtok modifies strings, keep string const
screenpart= findintable(screenparttable, strtok(s, ":"), _("screen part"));
colors = strtok(nullptr, ":");
attributes = strtok(nullptr, ":");
if ((colors == nullptr || ! strlen(colors)) &&
(attributes == nullptr || ! strlen(attributes))) {
ohshit(_("missing color specification"));
}
if (colors != nullptr && strlen(colors)) {
char *colorname;
colorname = strtok(colors, ",");
if (colorname != nullptr && strlen(colorname)) {
// normalize attributes to prevent confusion
color[screenpart].attr= A_NORMAL;
color[screenpart].fore = findintable(colortable, colorname, _("color"));
}
colorname = strtok(nullptr, ",");
if (colorname != nullptr && strlen(colorname)) {
color[screenpart].attr= A_NORMAL;
color[screenpart].back = findintable(colortable, colorname, _("color"));
}
}
if (attributes != nullptr && strlen(attributes)) {
for (char *attrib = strtok(attributes, "+");
attrib != nullptr && strlen(attrib);
attrib = strtok(nullptr, "+")) {
int aval;
aval = findintable(attrtable, attrib, _("color attribute"));
if (aval == A_NORMAL) // set to normal
color[screenpart].attr= aval;
else // add to existing attribs
color[screenpart].attr= color[screenpart].attr | aval;
}
}
free(s);
}
} /* End of extern "C" */
static const struct cmdinfo cmdinfos[]= {
{ "admindir", 0, 1, nullptr, nullptr, set_admindir, 1 },
{ "instdir", 0, 1, nullptr, nullptr, set_instdir, 1 },
{ "root", 0, 1, nullptr, nullptr, set_root, 1 },
{ "debug", 'D', 1, nullptr, nullptr, set_debug },
{ "expert", 'E', 0, nullptr, nullptr, set_expert },
{ "help", '?', 0, nullptr, nullptr, usage },
{ "version", 0, 0, nullptr, nullptr, printversion },
{ "color", 0, 1, nullptr, nullptr, set_color }, /* US spelling */
{ "colour", 0, 1, nullptr, nullptr, set_color }, /* UK spelling */
{ nullptr, 0, 0, nullptr, nullptr, nullptr }
};
static bool cursesareon = false;
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);
fprintf(stderr,
_("Set your TERM variable correctly, use a better terminal,\n"
"or make do with the per-package management tool %s.\n"),
DPKG);
ohshit(_("terminal lacks necessary features, giving up"));
}
}
cursesareon = true;
}
void cursesoff() {
if (cursesareon) {
clear();
refresh();
endwin();
}
cursesareon = false;
}
urqresult urq_list(void) {
modstatdb_open(static_cast<modstatdb_rw>(msdbrw_writeifposs |
msdbrw_available_readonly));
curseson();
packagelist *l= new packagelist(&packagelistbindings);
l->resolvesuggest();
l->display();
delete l;
modstatdb_shutdown();
return urqr_normal;
}
static void
display_menu_entry(int i, int so)
{
const menuentry *me= &menuentries[i];
varbuf buf;
buf.add_fmt(" %c %d. %-11.11s %-80.80s ",
so ? '*' : ' ', i,
gettext(me->option),
gettext(me->menuent));
int x, y DPKG_ATTR_UNUSED;
getmaxyx(stdscr,y,x);
attrset(so ? A_REVERSE : A_NORMAL);
mvaddnstr(i + 2, 0, buf.str(), x - 1);
attrset(A_NORMAL);
}
static int
refreshmenu(void)
{
curseson(); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
int x, y DPKG_ATTR_UNUSED;
getmaxyx(stdscr,y,x);
varbuf buf;
buf.add_fmt(gettext(programdesc), DSELECT, PACKAGE_RELEASE);
clear();
attrset(A_BOLD);
mvaddnstr(0, 0, buf.str(), x - 1);
attrset(A_NORMAL);
const struct menuentry *mep; int i;
for (mep=menuentries, i=0; mep->option && mep->menuent; mep++, i++)
display_menu_entry(i, 0);
attrset(A_BOLD);
addstr(_("\n\n"
"Move around with ^P and ^N, cursor keys, initial letters, or digits;\n"
"Press <enter> to confirm selection. ^L redraws screen.\n\n"));
attrset(A_NORMAL);
addstr(_("Copyright (C) 1994-1996 Ian Jackson.\n"
"Copyright (C) 2000,2001 Wichert Akkerman.\n"));
addstr(gettext(licensestring));
modstatdb_init();
if (!modstatdb_can_lock())
addstr(_("\n\n"
"Read-only access: only preview of selections is available!"));
modstatdb_done();
return i;
}
urqresult urq_menu(void) {
int entries, c;
entries= refreshmenu();
int cursor=0;
display_menu_entry(0, 1);
for (;;) {
refresh();
do {
c= getch();
if (c == KEY_RESIZE) {
refreshmenu();
display_menu_entry(cursor, 1);
continue;
}
} while (c == ERR && errno == EINTR);
if (c==ERR) {
if(errno != 0)
ohshite(_("failed to getch in main menu"));
else {
clearok(stdscr, TRUE);
clear();
refreshmenu();
display_menu_entry(cursor, 1);
}
}
if (c == CTRL('n') || c == KEY_DOWN || c == ' ' || c == 'j') {
display_menu_entry(cursor, 0);
cursor++;
cursor %= entries;
display_menu_entry(cursor, 1);
} else if (c == CTRL('p') || c == KEY_UP || c == CTRL('h') ||
c==KEY_BACKSPACE || c==KEY_DC || c=='k') {
display_menu_entry(cursor, 0);
cursor += entries - 1;
cursor %= entries;
display_menu_entry(cursor, 1);
} else if (c=='\n' || c=='\r' || c==KEY_ENTER) {
clear(); refresh();
/* FIXME: trap errors in urq_... */
urqresult res = menuentries[cursor].fn();
switch (res) {
case urqr_quitmenu:
return urqr_quitmenu;
case urqr_normal:
cursor++; cursor %= entries;
case urqr_fail:
break;
default:
internerr("unknown menufn %d", res);
}
refreshmenu();
display_menu_entry(cursor, 1);
} else if (c == CTRL('l')) {
clearok(stdscr, TRUE);
clear();
refreshmenu();
display_menu_entry(cursor, 1);
} else if (isdigit(c)) {
char buf[2]; buf[0]=c; buf[1]=0; c=atoi(buf);
if (c < entries) {
display_menu_entry(cursor, 0);
cursor = c;
display_menu_entry(cursor, 1);
} else {
beep();
}
} else if (isalpha(c)) {
c= tolower(c);
int i = 0;
while (i < entries && gettext(menuentries[i].key)[0] != c)
i++;
if (i < entries) {
display_menu_entry(cursor, 0);
cursor = i;
display_menu_entry(cursor, 1);
} else {
beep();
}
} else {
beep();
}
}
}
urqresult urq_quit(void) {
/* FIXME: check packages OK. */
return urqr_quitmenu;
}
static void
dselect_catch_fatal_error()
{
cursesoff();
catch_fatal_error();
}
int
main(int, const char *const *argv)
{
dpkg_locales_init(DSELECT);
dpkg_set_progname(DSELECT);
push_error_context_func(dselect_catch_fatal_error, print_fatal_error, nullptr);
dpkg_options_load(DSELECT, cmdinfos);
dpkg_options_parse(&argv, cmdinfos, printforhelp);
debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
if (*argv) {
const char *a;
while ((a = *argv++) != nullptr) {
const menuentry *me = menuentries;
while (me->command && strcmp(me->command, a))
me++;
if (!me->command)
badusage(_("unknown action string '%.50s'"), a);
me->fn();
}
} else {
urq_menu();
}
cursesoff();
dpkg_program_done();
dpkg_locales_done();
return(0);
}

109
dselect/methkeys.cc Normal file
View file

@ -0,0 +1,109 @@
/*
* dselect - Debian package maintenance user interface
* methkeys.cc - method list keybindings
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
#include "bindings.h"
const keybindings::interpretation methodlist_kinterps[] = {
{ "up", &methodlist::kd_up, nullptr, qa_noquit },
{ "down", &methodlist::kd_down, nullptr, qa_noquit },
{ "top", &methodlist::kd_top, nullptr, qa_noquit },
{ "bottom", &methodlist::kd_bottom, nullptr, qa_noquit },
{ "scrollon", &methodlist::kd_scrollon, nullptr, qa_noquit },
{ "scrollback", &methodlist::kd_scrollback, nullptr, qa_noquit },
{ "iscrollon", &methodlist::kd_iscrollon, nullptr, qa_noquit },
{ "iscrollback", &methodlist::kd_iscrollback, nullptr, qa_noquit },
{ "scrollon1", &methodlist::kd_scrollon1, nullptr, qa_noquit },
{ "scrollback1", &methodlist::kd_scrollback1, nullptr, qa_noquit },
{ "iscrollon1", &methodlist::kd_iscrollon1, nullptr, qa_noquit },
{ "iscrollback1", &methodlist::kd_iscrollback1, nullptr, qa_noquit },
{ "panon", &methodlist::kd_panon, nullptr, qa_noquit },
{ "panback", &methodlist::kd_panback, nullptr, qa_noquit },
{ "panon1", &methodlist::kd_panon1, nullptr, qa_noquit },
{ "panback1", &methodlist::kd_panback1, nullptr, qa_noquit },
{ "help", &methodlist::kd_help, nullptr, qa_noquit },
{ "search", &methodlist::kd_search, nullptr, qa_noquit },
{ "searchagain", &methodlist::kd_searchagain, nullptr, qa_noquit },
{ "redraw", &methodlist::kd_redraw, nullptr, qa_noquit },
{ "select-and-quit", &methodlist::kd_quit, nullptr, qa_quitchecksave },
{ "abort", &methodlist::kd_abort, nullptr, qa_quitnochecksave },
{ nullptr, nullptr, nullptr, qa_noquit }
};
const keybindings::orgbinding methodlist_korgbindings[]= {
{ 'j', "down" }, // vi style
//{ 'n', "down" }, // no style
{ KEY_DOWN, "down" },
{ 'k', "up" }, // vi style
//{ 'p', "up" }, // no style
{ KEY_UP, "up" },
{ CTRL('f'), "scrollon" }, // vi style
{ 'N', "scrollon" },
{ KEY_NPAGE, "scrollon" },
{ ' ', "scrollon" },
{ CTRL('b'), "scrollback" }, // vi style
{ 'P', "scrollback" },
{ KEY_PPAGE, "scrollback" },
{ KEY_BACKSPACE, "scrollback" },
{ 0177,/*DEL*/ "scrollback" },
{ CTRL('h'), "scrollback" },
{ CTRL('n'), "scrollon1" },
{ CTRL('p'), "scrollback1" },
{ 't', "top" },
{ KEY_HOME, "top" },
{ 'e', "bottom" },
{ KEY_LL, "bottom" },
{ KEY_END, "bottom" },
{ 'u', "iscrollback" },
{ 'd', "iscrollon" },
{ CTRL('u'), "iscrollback1" },
{ CTRL('d'), "iscrollon1" },
{ 'B', "panback" },
{ KEY_LEFT, "panback" },
{ 'F', "panon" },
{ KEY_RIGHT, "panon" },
{ CTRL('b'), "panback1" },
{ CTRL('f'), "panon1" },
{ '?', "help" },
{ KEY_HELP, "help" },
{ KEY_F(1), "help" },
{ '/', "search" },
{ 'n', "searchagain" },
{ '\\', "searchagain" },
{ CTRL('l'), "redraw" },
{ KEY_ENTER, "select-and-quit" },
{ '\r', "select-and-quit" },
{ 'x', "abort" },
{ 'X', "abort" },
{ 'Q', "abort" },
{ -1, nullptr }
};

229
dselect/methlist.cc Normal file
View file

@ -0,0 +1,229 @@
/*
* dselect - Debian package maintenance user interface
* methlist.cc - list of access methods and options
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/string.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.str();
}
void methodlist::kd_abort() { }
void methodlist::kd_quit() {
debug(dbg_general, "methodlist[%p]::kd_quit() setting coption=%p",
this, table[cursorline]);
coption= table[cursorline];
}
void methodlist::setheights() {
debug(dbg_general, "methodlist[%p]::setheights()", this);
baselist::setheights();
list_height++;
}
void methodlist::setwidths() {
debug(dbg_general, "methodlist[%p]::setwidths()", this);
col_cur_x = 0;
add_column(col_status, " ", 1);
add_column(col_name, _("Abbrev."), 14);
end_column(col_desc, _("Description"));
}
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.str());
pnoutrefresh(thisstatepad, 0,0, thisstate_row,0,
thisstate_row, min(total_width - 1, xmax - 1));
}
void methodlist::redraw1itemsel(int index, int selected) {
int i;
const char *p;
wattrset(listpad, part_attr[selected ? listsel : list]);
mvwaddch(listpad,index,0,
table[index] == coption ? '*' : ' ');
wattrset(listpad, part_attr[selected ? listsel : list]);
draw_column_sep(col_name, index);
draw_column_item(col_name, index, table[index]->name.str());
draw_column_sep(col_desc, index);
i = col_desc.width;
p = table[index]->summary.str();
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, part_attr[colheads]);
mywerase(colheadspad);
draw_column_head(col_status);
draw_column_head(col_name);
draw_column_head(col_desc);
}
refreshcolheads();
}
methodlist::methodlist() : baselist(&methodlistbindings) {
int newcursor= -1;
debug(dbg_general, "methodlist[%p]::methodlist()", this);
table= new struct dselect_option*[noptions];
struct dselect_option *opt, **ip;
for (opt=options, ip=table, nitems=0; opt; opt=opt->next, nitems++) {
if (opt == coption) {
if (newcursor != -1)
internerr("multiple methods with same index");
newcursor = nitems;
}
*ip++= opt;
}
if (nitems != noptions)
internerr("inconsistent number of items: ntimes=%d != noptions=%d",
nitems, noptions);
if (newcursor==-1) newcursor= 0;
setcursor(newcursor);
debug(dbg_general, "methodlist[%p]::methodlist done; noptions=%d",
this, noptions);
}
methodlist::~methodlist() {
debug(dbg_general, "methodlist[%p]::~methodlist()", this);
delete[] table;
}
quitaction methodlist::display() {
int response;
const keybindings::interpretation *interp;
debug(dbg_general, "methodlist[%p]::display()", this);
startdisplay();
debug(dbg_general, "methodlist[%p]::display() entering loop", this);
for (;;) {
if (whatinfo_height) wcursyncup(whatinfowin);
if (doupdate() == ERR) ohshite(_("doupdate failed"));
do {
response = getch();
if (response == KEY_RESIZE) {
resize_window();
continue;
}
} while (response == ERR && errno == EINTR);
if (response == ERR) ohshite(_("getch failed"));
interp= (*bindings)(response);
debug(dbg_general, "methodlist[%p]::display() response=%d interp=%s",
this, response, interp ? interp->action : "[none]");
if (!interp)
continue;
(this->*(interp->mfn))();
if (interp->qa != qa_noquit) break;
}
enddisplay();
debug(dbg_general, "methodlist[%p]::display() done", this);
return interp->qa;
}
void methodlist::itd_description() {
whatinfovb += _("Explanation");
wattrset(infopad, part_attr[info_head]);
waddstr(infopad, table[cursorline]->name.str());
waddstr(infopad," - ");
waddstr(infopad, table[cursorline]->summary.str());
wattrset(infopad, part_attr[info_body]);
const char *m = table[cursorline]->description.str();
if (str_is_unset(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);
debug(dbg_general, "methodlist[%p]::redrawinfo()", this);
itd_description();
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;
}

260
dselect/method.cc Normal file
View file

@ -0,0 +1,260 @@
/*
* dselect - Debian package maintenance user interface
* method.cc - access method handling
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2001,2002 Wichert Akkerman <wakkerma@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/subproc.h>
#include <dpkg/command.h>
#include "dselect.h"
#include "method.h"
static const char *const methoddirectories[]= {
LIBDIR "/" METHODSDIR,
LOCALLIBDIR "/" METHODSDIR,
nullptr
};
static char *methodlockfile = nullptr;
static int methlockfd= -1;
static void
sthfailed(const char * reasoning)
{
curseson();
clear();
printw("\n\n%s: %s\n", DSELECT, reasoning);
attrset(A_BOLD);
addstr(_("\nPress <enter> to continue."));
attrset(A_NORMAL);
refresh(); getch();
}
static void cu_unlockmethod(int, void**) {
struct flock fl;
if (methodlockfile == nullptr)
internerr("method lock file is nullptr");
if (methlockfd < 0)
internerr("method lock fd is %d < 0", methlockfd);
fl.l_type=F_UNLCK; fl.l_whence= SEEK_SET; fl.l_start=fl.l_len=0;
if (fcntl(methlockfd, F_SETLK, &fl) < 0)
sthfailed(_("cannot unlock access method area"));
}
static enum urqresult ensureoptions(void) {
dselect_option *newoptions;
int nread;
if (!options) {
newoptions = nullptr;
nread= 0;
for (const char *const *ccpp = methoddirectories; *ccpp; ccpp++)
readmethods(*ccpp, &newoptions, &nread);
if (!newoptions) {
sthfailed(_("no access methods are available"));
return urqr_fail;
}
options= newoptions;
noptions= nread;
}
return urqr_normal;
}
static enum urqresult lockmethod(void) {
struct flock fl;
if (methodlockfile == nullptr)
methodlockfile = dpkg_db_get_path(METHLOCKFILE);
if (methlockfd < 0) {
methlockfd= open(methodlockfile, O_RDWR|O_CREAT|O_TRUNC, 0660);
if (methlockfd < 0) {
if ((errno == EPERM) || (errno == EACCES)) {
sthfailed(_("requested operation requires superuser privilege"));
return urqr_fail;
}
sthfailed(_("cannot open or create access method lockfile"));
return urqr_fail;
}
}
fl.l_type=F_WRLCK; fl.l_whence=SEEK_SET; fl.l_start=fl.l_len=0;
if (fcntl(methlockfd, F_SETLK, &fl) < 0) {
if (errno == EACCES || errno == EAGAIN) {
sthfailed(_("the access method area is already locked"));
return urqr_fail;
}
sthfailed(_("cannot lock access method area"));
return urqr_fail;
}
push_cleanup(cu_unlockmethod, ~0, 0);
return urqr_normal;
}
static urqresult
falliblesubprocess(struct command *cmd)
{
pid_t pid;
int i, c;
cursesoff();
subproc_signals_ignore(cmd->name);
pid = subproc_fork();
if (pid == 0) {
subproc_signals_cleanup(0, nullptr);
command_exec(cmd);
}
fprintf(stderr, "\n");
i = subproc_reap(pid, cmd->name, SUBPROC_WARN);
subproc_signals_restore();
if (i == 0) {
sleep(1);
return urqr_normal;
}
fprintf(stderr,_("Press <enter> to continue.\n"));
m_output(stderr, _("<standard error>"));
do {
c = fgetc(stdin);
} while ((c == EOF && errno == EINTR) || (c != '\n' && c != EOF));
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;
ur=lockmethod(); if (ur != urqr_normal) return ur;
getcurrentopt();
if (coption) {
struct command cmd;
varbuf cmdpath;
cmdpath += coption->meth->path;
cmdpath += exepath;
command_init(&cmd, cmdpath.str(), name);
command_add_args(&cmd, exepath, dpkg_db_get_dir(),
coption->meth->name.str(), coption->name.str(), nullptr);
ur = falliblesubprocess(&cmd);
command_destroy(&cmd);
} else {
sthfailed(_("no access method is selected or configured"));
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) {
urqresult ur;
struct command cmd;
command_init(&cmd, DPKG, name);
command_add_args(&cmd, DPKG, "--admindir", dpkg_db_get_dir(), "--pending",
dpkgmode, nullptr);
cursesoff();
printf(_("running %s %s ...\n"), "dpkg --pending", dpkgmode);
fflush(stdout);
ur = falliblesubprocess(&cmd);
command_destroy(&cmd);
return ur;
}
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;
ur=lockmethod(); if (ur != urqr_normal) return ur;
getcurrentopt();
curseson();
methodlist *l= new methodlist();
qa= l->display();
delete l;
if (qa == qa_quitchecksave) {
struct command cmd;
varbuf cmdpath;
cmdpath += coption->meth->path;
cmdpath += METHODSETUPSCRIPT;
command_init(&cmd, cmdpath.str(), _("query/setup script"));
command_add_args(&cmd, METHODSETUPSCRIPT, dpkg_db_get_dir(),
coption->meth->name.str(), coption->name.str(), nullptr);
ur = falliblesubprocess(&cmd);
command_destroy(&cmd);
if (ur == urqr_normal) writecurrentopt();
} else {
ur= urqr_fail;
}
pop_cleanup(ehflag_normaltidy);
return ur;
}

96
dselect/method.h Normal file
View file

@ -0,0 +1,96 @@
/*
* dselect - Debian package maintenance user interface
* method.h - access method handling declarations
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef METHOD_H
#define METHOD_H
#define CMETHOPTFILE "cmethopt"
#define METHLOCKFILE "methlock"
#define METHODSDIR "methods"
#define IMETHODMAXLEN 50
#define IOPTIONMAXLEN IMETHODMAXLEN
#define METHODOPTIONSFILE "names"
#define METHODSETUPSCRIPT "setup"
#define METHODUPDATESCRIPT "update"
#define METHODINSTALLSCRIPT "install"
#define OPTIONSDESCPFX "desc."
#define OPTIONINDEXMAXLEN 5
struct method {
struct method *next, *prev;
varbuf name, path;
};
struct dselect_option {
dselect_option *next;
method *meth;
varbuf index;
varbuf name;
varbuf summary;
varbuf description;
};
class methodlist : public baselist {
protected:
column col_status;
column col_name;
column col_desc;
// Table of methods
struct dselect_option **table;
// Information displays
void itd_description();
// Define these virtuals
void redraw1itemsel(int index, int selected) override;
void redrawcolheads() override;
void redrawthisstate() override;
void redrawinfo() override;
void redrawtitle() override;
void setwidths() override;
void setheights() override;
const char *itemname(int index) override;
const struct helpmenuentry *helpmenulist() override;
public:
// Keybinding functions */
void kd_quit();
void kd_abort();
methodlist();
methodlist(const methodlist &) = delete;
methodlist &operator =(const methodlist &) = delete;
quitaction display();
~methodlist() override;
};
extern int noptions;
extern struct dselect_option *options, *coption;
extern struct method *methods;
void readmethods(const char *pathbase, dselect_option **optionspp, int *nread);
void getcurrentopt();
void writecurrentopt();
#endif /* METHOD_H */

View file

@ -0,0 +1,267 @@
# 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, see <https://www.gnu.org/licenses/>.
=encoding utf8
=head1 NAME
Dselect::Method - dselect method support
=head1 DESCRIPTION
This module provides support functions to implement methods.
B<Note>: This is a private module, its API can change at any time.
=cut
package Dselect::Method 0.01;
use strict;
use warnings;
our @EXPORT = qw(
%CONFIG
yesno
nb
view_mirrors
add_site
edit_site
edit_config
read_config
store_config
);
use Exporter qw(import);
use Carp;
eval q{
use Data::Dumper;
use Dpkg::File;
};
if ($@) {
warn "Missing Dpkg modules required by the access method.\n\n";
exit 1;
}
our %CONFIG;
sub yesno {
my ($d, $msg) = @_;
my ($res, $r);
$r = -1;
$r = 0 if $d eq 'n';
$r = 1 if $d eq 'y';
croak 'incorrect usage of yesno, stopped' if $r == -1;
while (1) {
print $msg, " [$d]: ";
$res = <STDIN>;
$res =~ /^[Yy]/ and return 1;
$res =~ /^[Nn]/ and return 0;
$res =~ /^[ \t]*$/ and return $r;
print "Please enter one of the letters 'y' or 'n'\n";
}
}
sub nb {
my $nb = shift;
if ($nb > 1024 ** 2) {
return sprintf '%.2fM', $nb / 1024 ** 2;
} elsif ($nb > 1024) {
return sprintf '%.2fk', $nb / 1024;
} else {
return sprintf '%.2fb', $nb;
}
}
sub read_config {
my $vars = shift;
my ($code, $conf);
eval {
$code = file_slurp($vars);
};
if ($@) {
warn "$@\n";
die "Try to relaunch the 'Access' step in dselect, thanks.\n";
}
my $VAR1; ## no critic (Variables::ProhibitUnusedVariables)
$conf = eval $code;
die "couldn't eval $vars content: $@\n" if $@;
if (ref($conf) =~ /HASH/) {
foreach (keys %{$conf}) {
$CONFIG{$_} = $conf->{$_};
}
} else {
print "Bad $vars file : removing it.\n";
print "Please relaunch the 'Access' step in dselect. Thanks.\n";
unlink $vars;
exit 0;
}
}
sub store_config {
my $vars = shift;
# Check that config is completed
return if not $CONFIG{done};
file_dump($vars, Dumper(\%CONFIG));
}
sub view_mirrors {
print <<'MIRRORS';
Please see <https://www.debian.org/mirror/list> for a current
list of Debian mirror sites.
MIRRORS
}
sub edit_config {
my ($method, $methdir) = @_;
my $i;
# Get a config for the sites
while (1) {
$i = 1;
print "\n\nList of selected $method sites :\n";
foreach (@{$CONFIG{site}}) {
print "$i. $method://$_->[0]$_->[1] @{$_->[2]}\n";
$i++;
}
print "\nEnter a command (a=add e=edit d=delete q=quit m=mirror list) \n";
print 'eventually followed by a site number : ';
chomp($_ = <STDIN>);
/q/i && last;
/a/i && add_site($method);
/d\s*(\d+)/i && do {
splice(@{$CONFIG{site}}, $1 - 1, 1) if $1 <= @{$CONFIG{site}};
next;
};
/e\s*(\d+)/i && do {
edit_site($method, $CONFIG{site}[$1 - 1]) if $1 <= @{$CONFIG{site}};
next;
};
/m/i && view_mirrors();
}
print "\n";
$CONFIG{use_auth_proxy} = yesno($CONFIG{use_auth_proxy} ? 'y' : 'n',
'Go through an authenticated proxy');
if ($CONFIG{use_auth_proxy}) {
print "\nEnter proxy hostname [$CONFIG{proxyhost}] : ";
chomp($_ = <STDIN>);
$CONFIG{proxyhost} = $_ || $CONFIG{proxyhost};
print "\nEnter proxy log name [$CONFIG{proxylogname}] : ";
chomp($_ = <STDIN>);
$CONFIG{proxylogname} = $_ || $CONFIG{proxylogname};
print "\nEnter proxy password [$CONFIG{proxypassword}] : ";
chomp($_ = <STDIN>);
$CONFIG{proxypassword} = $_ || $CONFIG{proxypassword};
}
print "\nEnter directory to download binary package files to\n";
print "(relative to $methdir)\n";
while (1) {
print "[$CONFIG{dldir}] : ";
chomp($_ = <STDIN>);
s{/$}{};
$CONFIG{dldir} = $_ if $_;
last if -d "$methdir/$CONFIG{dldir}";
print "$methdir/$CONFIG{dldir} is not a directory !\n";
}
}
sub add_site {
my $method = shift;
my $pas = 1;
my $user = 'anonymous';
my $email = qx(whoami);
chomp $email;
$email .= '@' . qx(cat /etc/mailname || dnsdomainname);
chomp $email;
my $dir = '/debian';
push @{$CONFIG{site}}, [
'',
$dir,
[
'dists/stable/main',
'dists/stable/contrib',
'dists/stable/non-free-firmware',
'dists/stable/non-free',
],
$pas,
$user,
$email,
];
edit_site($method, $CONFIG{site}[@{$CONFIG{site}} - 1]);
}
sub edit_site {
my ($method, $site) = @_;
local $_;
print "\nEnter $method site [$site->[0]] : ";
chomp($_ = <STDIN>);
$site->[0] = $_ || $site->[0];
print "\nUse passive mode [" . ($site->[3] ? 'y' : 'n') . '] : ';
chomp($_ = <STDIN>);
$site->[3] = (/y/i ? 1 : 0) if $_;
print "\nEnter username [$site->[4]] : ";
chomp($_ = <STDIN>);
$site->[4] = $_ || $site->[4];
print <<"EOF";
If you are using anonymous $method to retrieve files, enter your email
address for use as a password. Otherwise enter your password,
or "?" if you want the $method method to prompt you each time.
EOF
print "Enter password [$site->[5]] : ";
chomp($_ = <STDIN>);
$site->[5] = $_ || $site->[5];
print "\nEnter debian directory [$site->[1]] : ";
chomp($_ = <STDIN>);
$site->[1] = $_ || $site->[1];
print "\nEnter space separated list of distributions to get\n";
print "[@{$site->[2]}] : ";
chomp($_ = <STDIN>);
$site->[2] = [ split(/\s+/) ] if $_;
}
=head1 CHANGES
=head2 Version 0.xx
This is a private module.
=cut
1;
__END__

View file

@ -0,0 +1,232 @@
# 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, see <https://www.gnu.org/licenses/>.
=encoding utf8
=head1 NAME
Dselect::Method::Ftp - dselect FTP method support
=head1 DESCRIPTION
This module provides support functions for the FTP method.
B<Note>: This is a private module, its API can change at any time.
=cut
package Dselect::Method::Ftp 0.01;
use strict;
use warnings;
our @EXPORT = qw(
do_connect
do_mdtm
);
use Exporter qw(import);
use Carp;
eval q{
use Net::FTP;
use Data::Dumper;
};
if ($@) {
warn "Missing Net::FTP modules required by the FTP access method.\n\n";
exit 1;
}
sub do_connect {
my (%opts) = @_;
my($rpass,$remotehost,$remoteuser,$ftp);
TRY_CONNECT:
while(1) {
my $exit = 0;
if ($opts{useproxy}) {
$remotehost = $opts{proxyhost};
$remoteuser = $opts{username} . '@' . $opts{ftpsite};
} else {
$remotehost = $opts{ftpsite};
$remoteuser = $opts{username};
}
print "Connecting to $opts{ftpsite}...\n";
$ftp = Net::FTP->new($remotehost, Passive => $opts{passive});
if(!$ftp || !$ftp->ok) {
print "Failed to connect\n";
$exit = 1;
}
if (!$exit) {
# $ftp->debug(1);
if ($opts{useproxy}) {
print "Login on $opts{proxyhost}...\n";
$ftp->_USER($opts{proxylogname});
$ftp->_PASS($opts{proxypassword});
}
print "Login as $opts{username}...\n";
if ($opts{password} eq '?') {
print 'Enter password for ftp: ';
system('stty', '-echo');
$rpass = <STDIN>;
chomp $rpass;
print "\n";
system('stty', 'echo');
} else {
$rpass = $opts{password};
}
if(!$ftp->login($remoteuser, $rpass))
{ print $ftp->message() . "\n"; $exit = 1; }
}
if (!$exit) {
print "Setting transfer mode to binary...\n";
if(!$ftp->binary()) { print $ftp->message . "\n"; $exit = 1; }
}
if (!$exit) {
print "Cd to '$opts{ftpdir}'...\n";
if (!$ftp->cwd($opts{ftpdir})) {
print $ftp->message . "\n";
$exit = 1;
}
}
if ($exit) {
if (yesno ('y', 'Retry connection at once')) {
next TRY_CONNECT;
} else {
die 'error';
}
}
last TRY_CONNECT;
}
# if(!$ftp->pasv()) { print $ftp->message . "\n"; die 'error'; }
return $ftp;
}
##############################
# assume server supports MDTM - will be adjusted if needed
my $has_mdtm = 1;
my %months = (
Jan => 0,
Feb => 1,
Mar => 2,
Apr => 3,
May => 4,
Jun => 5,
Jul => 6,
Aug => 7,
Sep => 8,
Oct => 9,
Nov => 10,
Dec => 11,
);
my $ls_l_re = qr<
([^ ]+\ *){5} # Perms, Links, User, Group, Size
[^ ]+ # Blanks
\ ([A-Z][a-z]{2}) # Month name (abbreviated)
\ ([0-9 ][0-9]) # Day of month
\ ([0-9 ][0-9][:0-9][0-9]{2}) # Filename
>x;
sub do_mdtm {
my ($ftp, $file) = @_;
my ($time);
#if ($has_mdtm) {
$time = $ftp->mdtm($file);
# my $code = $ftp->code();
# my $message = $ftp->message();
# print " [ $code: $message ] ";
if ($ftp->code() == 502 || # MDTM not implemented
$ftp->code() == 500) { # command not understood (SUN firewall)
$has_mdtm = 0;
} elsif (!$ftp->ok()) {
return;
}
#}
if (! $has_mdtm) {
require Time::Local;
my @files = $ftp->dir($file);
if (($#files == -1) ||
($ftp->code == 550)) { # No such file or directory
return;
}
# my $code = $ftp->code();
# my $message = $ftp->message();
# print " [ $code: $message ] ";
# print "[$#files]";
# get the date components from the output of 'ls -l'
if ($files[0] =~ $ls_l_re) {
my($month_name, $day, $year_or_time, $month, $hours, $minutes,
$year);
# what we can read
$month_name = $2;
$day = 0 + $3;
$year_or_time = $4;
# translate the month name into number
$month = $months{$month_name};
# recognize time or year, and compute missing one
if ($year_or_time =~ /([0-9]{2}):([0-9]{2})/) {
$hours = 0 + $1; $minutes = 0 + $2;
my @this_date = gmtime(time());
my $this_month = $this_date[4];
my $this_year = $this_date[5];
if ($month > $this_month) {
$year = $this_year - 1;
} else {
$year = $this_year;
}
} elsif ($year_or_time =~ / [0-9]{4}/) {
$hours = 0; $minutes = 0;
$year = $year_or_time - 1900;
} else {
die 'cannot parse year-or-time';
}
# build a system time
$time = Time::Local::timegm(0, $minutes, $hours, $day, $month, $year);
} else {
die 'regex match failed on LIST output';
}
}
return $time;
}
=head1 CHANGES
=head2 Version 0.xx
This is a private module.
=cut
1;
__END__

View file

@ -0,0 +1,54 @@
## Process this file with automake to produce Makefile.in
nobase_dist_perllib_DATA = \
Dselect/Method.pm \
Dselect/Method/Ftp.pm \
# EOL
nobase_dist_methods_DATA = \
file/names \
file/desc.file \
ftp/names \
ftp/desc.ftp \
media/names \
media/desc.media \
# EOL
nobase_methods_SCRIPTS = \
file/install \
file/setup \
file/update \
ftp/install \
ftp/setup \
ftp/update \
media/install \
media/setup \
media/update \
# EOL
EXTRA_DIST = \
file/setup.sh \
file/update.sh \
file/install.sh \
ftp/setup.pl \
ftp/update.pl \
ftp/install.pl \
media/setup.sh \
media/update.sh \
media/install.sh \
media/README.media \
# EOL
CLEANFILES = \
$(nobase_methods_SCRIPTS) \
# EOL
SUFFIXES =
include $(top_srcdir)/build-aux/subst.am
install-data-local:
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/mnt
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/file
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/ftp
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/media

782
dselect/methods/Makefile.in Normal file
View file

@ -0,0 +1,782 @@
# Makefile.in generated by automake 1.17 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2024 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
#
# Build time variable substitution for generated files.
#
# Shell support.
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
am__rm_f = rm -f $(am__rm_f_notfound)
am__rm_rf = rm -rf $(am__rm_f_notfound)
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = dselect/methods
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/build-to-host.m4 \
$(top_srcdir)/m4/dpkg-arch.m4 $(top_srcdir)/m4/dpkg-build.m4 \
$(top_srcdir)/m4/dpkg-compiler.m4 \
$(top_srcdir)/m4/dpkg-coverage.m4 \
$(top_srcdir)/m4/dpkg-funcs.m4 \
$(top_srcdir)/m4/dpkg-headers.m4 $(top_srcdir)/m4/dpkg-libs.m4 \
$(top_srcdir)/m4/dpkg-linker.m4 $(top_srcdir)/m4/dpkg-progs.m4 \
$(top_srcdir)/m4/dpkg-types.m4 \
$(top_srcdir)/m4/dpkg-unicode.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/host-cpu-c-abi.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(nobase_dist_methods_DATA) \
$(nobase_dist_perllib_DATA) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
{ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \
}
am__installdirs = "$(DESTDIR)$(methodsdir)" "$(DESTDIR)$(methodsdir)" \
"$(DESTDIR)$(perllibdir)"
SCRIPTS = $(nobase_methods_SCRIPTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
DATA = $(nobase_dist_methods_DATA) $(nobase_dist_perllib_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/build-aux/subst.am
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOM4TE = @AUTOM4TE@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_DEVEL_DOCS = @BUILD_DEVEL_DOCS@
BZ2_LIBS = @BZ2_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CSCOPE = @CSCOPE@
CTAGS = @CTAGS@
CURSES_LIBS = @CURSES_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEB_DEFAULT_COMPRESSOR = @DEB_DEFAULT_COMPRESSOR@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DPKG_DEFAULT_PAGER = @DPKG_DEFAULT_PAGER@
DPKG_DEFAULT_SHELL = @DPKG_DEFAULT_SHELL@
DPKG_PAGER = @DPKG_PAGER@
DPKG_SHELL = @DPKG_SHELL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FILECMD = @FILECMD@
GCOV = @GCOV@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GREP = @GREP@
HAVE_DOT = @HAVE_DOT@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INTLLIBS = @INTLLIBS@
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
KVM_LIBS = @KVM_LIBS@
LCOV = @LCOV@
LCOV_GENHTML = @LCOV_GENHTML@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LZMA_LIBS = @LZMA_LIBS@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MD_LIBS = @MD_LIBS@
MKDIR_P = @MKDIR_P@
MSGFMT = @MSGFMT@
MSGMERGE = @MSGMERGE@
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_BUG_WEB = @PACKAGE_BUG_WEB@
PACKAGE_COPYRIGHT_HOLDER = @PACKAGE_COPYRIGHT_HOLDER@
PACKAGE_CPAN_NAME = @PACKAGE_CPAN_NAME@
PACKAGE_DIST_IS_RELEASE = @PACKAGE_DIST_IS_RELEASE@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_RELEASE_DATE = @PACKAGE_RELEASE_DATE@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VCS_ID = @PACKAGE_VCS_ID@
PACKAGE_VCS_TYPE = @PACKAGE_VCS_TYPE@
PACKAGE_VCS_URL = @PACKAGE_VCS_URL@
PACKAGE_VCS_WEB = @PACKAGE_VCS_WEB@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATCH = @PATCH@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
PERL_COVER = @PERL_COVER@
PERL_COVERAGE = @PERL_COVERAGE@
PERL_LIBDIR = @PERL_LIBDIR@
PERL_MIN_VERSION = @PERL_MIN_VERSION@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PO4A = @PO4A@
POD2MAN = @POD2MAN@
POSUB = @POSUB@
PS_LIBS = @PS_LIBS@
RANLIB = @RANLIB@
RT_LIBS = @RT_LIBS@
SED = @SED@
SELINUX_CFLAGS = @SELINUX_CFLAGS@
SELINUX_LIBS = @SELINUX_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
STRIP = @STRIP@
TAR = @TAR@
USE_NLS = @USE_NLS@
USE_PO4A = @USE_PO4A@
USE_UNICODE = @USE_UNICODE@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
ZSTD_LIBS = @ZSTD_LIBS@
Z_LIBS = @Z_LIBS@
Z_NG_LIBS = @Z_NG_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
aclocaldir = @aclocaldir@
admindir = @admindir@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__rm_f_notfound = @am__rm_f_notfound@
am__tar = @am__tar@
am__untar = @am__untar@
am__xargs_n = @am__xargs_n@
backupsdir = @backupsdir@
bashcompletionsdir = @bashcompletionsdir@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
devlibdir = @devlibdir@
docdir = @docdir@
docspecdir = @docspecdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localedir_c = @localedir_c@
localedir_c_make = @localedir_c_make@
localstatedir = @localstatedir@
logdir = @logdir@
mandir = @mandir@
methodsdir = @methodsdir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
perllibdir = @perllibdir@
pkgconfdir = @pkgconfdir@
pkgconfigdir = @pkgconfigdir@
polkitactionsdir = @polkitactionsdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
zshcompletionsdir = @zshcompletionsdir@
nobase_dist_perllib_DATA = \
Dselect/Method.pm \
Dselect/Method/Ftp.pm \
# EOL
nobase_dist_methods_DATA = \
file/names \
file/desc.file \
ftp/names \
ftp/desc.ftp \
media/names \
media/desc.media \
# EOL
nobase_methods_SCRIPTS = \
file/install \
file/setup \
file/update \
ftp/install \
ftp/setup \
ftp/update \
media/install \
media/setup \
media/update \
# EOL
EXTRA_DIST = \
file/setup.sh \
file/update.sh \
file/install.sh \
ftp/setup.pl \
ftp/update.pl \
ftp/install.pl \
media/setup.sh \
media/update.sh \
media/install.sh \
media/README.media \
# EOL
CLEANFILES = \
$(nobase_methods_SCRIPTS) \
# EOL
SUFFIXES = .sh .pl
subst_shell_rules = "\
s{^ADMINDIR=.*$$}{ADMINDIR='$(admindir)'}; \
s{^BACKUPSDIR=.*$$}{BACKUPSDIR='$(backupsdir)'}; \
s{^PKGDATADIR_DEFAULT=.*$$}{PKGDATADIR_DEFAULT='$(pkgdatadir)'}; \
s{^version=['\"][^'\"]*[\"']}{version=\"$(PACKAGE_VERSION)\"}; \
s{^TAR=.*$$}{TAR='$(TAR)'}; \
"
subst_shell_filter = $(PERL) -p -e $(subst_shell_rules)
subst_shell_file = $(PERL) -i -p -e $(shell_subst_rules)
# Perl support.
# Note: We need to hex-escape '#' (0x23) to avoid portability issues with make.
subst_perl_rules = "\
s{^\x23!\s*/usr/bin/perl}{\x23!$(PERL)}; \
s{our \\\$$CONFDIR = .*;}{our \\\$$CONFDIR = '$(pkgconfdir)';}; \
s{our \\\$$ADMINDIR = .*;}{our \\\$$ADMINDIR = '$(admindir)';}; \
s{our \\\$$LIBDIR = .*;}{our \\\$$LIBDIR = '$(pkglibexecdir)';}; \
s{our \\\$$DATADIR = .*;}{our \\\$$DATADIR = '$(pkgdatadir)';}; \
s{our \\\$$PROGMAKE = .*;}{our \\\$$PROGMAKE = '$(MAKE)';}; \
s{our \\\$$PROGTAR = .*;}{our \\\$$PROGTAR = '$(TAR)';}; \
s{our \\\$$PROGPATCH = .*;}{our \\\$$PROGPATCH = '$(PATCH)';}; \
s{our \\\$$PROGVERSION = .*;}{our \\\$$PROGVERSION = '$(PACKAGE_VERSION)';}; \
"
subst_perl_filter = $(PERL) -p -e $(subst_perl_rules)
subst_perl_file = $(PERL) -i -p -e $(subst_perl_rules)
all: all-am
.SUFFIXES:
.SUFFIXES: .sh .pl
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/build-aux/subst.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dselect/methods/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign dselect/methods/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_srcdir)/build-aux/subst.am $(am__empty):
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-nobase_methodsSCRIPTS: $(nobase_methods_SCRIPTS)
@$(NORMAL_INSTALL)
@list='$(nobase_methods_SCRIPTS)'; test -n "$(methodsdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(methodsdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(methodsdir)" || exit 1; \
fi; \
$(am__nobase_strip_setup); \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n' \
-e "s|$$srcdirstrip/||" -e 'h;s|[^/]*$$||; s|^$$|.|' \
-e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) { files[d] = files[d] " " $$1; \
if (++n[d] == $(am__install_max)) { \
print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
else { print "f", d "/" $$4, $$1 } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
case $$type in \
d) echo " $(MKDIR_P) '$(DESTDIR)$(methodsdir)/$$dir'"; \
$(MKDIR_P) "$(DESTDIR)$(methodsdir)/$$dir" || exit $$?;; \
f) \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(methodsdir)$$dir'"; \
$(INSTALL_SCRIPT) $$files "$(DESTDIR)$(methodsdir)$$dir" || exit $$?; \
} \
;; esac \
; done
uninstall-nobase_methodsSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(nobase_methods_SCRIPTS)'; test -n "$(methodsdir)" || exit 0; \
$(am__nobase_strip_setup); \
files=`$(am__nobase_strip) \
-e 'h;s,.*/,,;$(transform);x;s|[^/]*$$||;G;s,\n,,'`; \
dir='$(DESTDIR)$(methodsdir)'; $(am__uninstall_files_from_dir)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-nobase_dist_methodsDATA: $(nobase_dist_methods_DATA)
@$(NORMAL_INSTALL)
@list='$(nobase_dist_methods_DATA)'; test -n "$(methodsdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(methodsdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(methodsdir)" || exit 1; \
fi; \
$(am__nobase_list) | while read dir files; do \
xfiles=; for file in $$files; do \
if test -f "$$file"; then xfiles="$$xfiles $$file"; \
else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
test -z "$$xfiles" || { \
test "x$$dir" = x. || { \
echo " $(MKDIR_P) '$(DESTDIR)$(methodsdir)/$$dir'"; \
$(MKDIR_P) "$(DESTDIR)$(methodsdir)/$$dir"; }; \
echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(methodsdir)/$$dir'"; \
$(INSTALL_DATA) $$xfiles "$(DESTDIR)$(methodsdir)/$$dir" || exit $$?; }; \
done
uninstall-nobase_dist_methodsDATA:
@$(NORMAL_UNINSTALL)
@list='$(nobase_dist_methods_DATA)'; test -n "$(methodsdir)" || list=; \
$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
dir='$(DESTDIR)$(methodsdir)'; $(am__uninstall_files_from_dir)
install-nobase_dist_perllibDATA: $(nobase_dist_perllib_DATA)
@$(NORMAL_INSTALL)
@list='$(nobase_dist_perllib_DATA)'; test -n "$(perllibdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(perllibdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(perllibdir)" || exit 1; \
fi; \
$(am__nobase_list) | while read dir files; do \
xfiles=; for file in $$files; do \
if test -f "$$file"; then xfiles="$$xfiles $$file"; \
else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
test -z "$$xfiles" || { \
test "x$$dir" = x. || { \
echo " $(MKDIR_P) '$(DESTDIR)$(perllibdir)/$$dir'"; \
$(MKDIR_P) "$(DESTDIR)$(perllibdir)/$$dir"; }; \
echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(perllibdir)/$$dir'"; \
$(INSTALL_DATA) $$xfiles "$(DESTDIR)$(perllibdir)/$$dir" || exit $$?; }; \
done
uninstall-nobase_dist_perllibDATA:
@$(NORMAL_UNINSTALL)
@list='$(nobase_dist_perllib_DATA)'; test -n "$(perllibdir)" || list=; \
$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
dir='$(DESTDIR)$(perllibdir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
cscope cscopelist:
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(SCRIPTS) $(DATA)
installdirs:
for dir in "$(DESTDIR)$(methodsdir)" "$(DESTDIR)$(methodsdir)" "$(DESTDIR)$(perllibdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
-$(am__rm_f) $(CLEANFILES)
distclean-generic:
-$(am__rm_f) $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-data-local install-nobase_dist_methodsDATA \
install-nobase_dist_perllibDATA install-nobase_methodsSCRIPTS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-nobase_dist_methodsDATA \
uninstall-nobase_dist_perllibDATA \
uninstall-nobase_methodsSCRIPTS
.MAKE: install-am install-strip
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
cscopelist-am ctags-am distclean distclean-generic \
distclean-libtool distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am \
install-data-local install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-nobase_dist_methodsDATA \
install-nobase_dist_perllibDATA install-nobase_methodsSCRIPTS \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags-am uninstall uninstall-am \
uninstall-nobase_dist_methodsDATA \
uninstall-nobase_dist_perllibDATA \
uninstall-nobase_methodsSCRIPTS
.PRECIOUS: Makefile
.sh: Makefile
@test -d `dirname $@` || $(MKDIR_P) `dirname $@`
$(AM_V_GEN) $(subst_shell_filter) <$< >$@
$(AM_V_at) chmod +x $@
.pl: Makefile
@test -d `dirname $@` || $(MKDIR_P) `dirname $@`
$(AM_V_GEN) $(subst_perl_filter) <$< >$@
$(AM_V_at) chmod +x $@
install-data-local:
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/mnt
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/file
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/ftp
$(MKDIR_P) $(DESTDIR)$(admindir)/methods/media
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
# Tell GNU make to disable its built-in pattern rules.
%:: %,v
%:: RCS/%,v
%:: RCS/%
%:: s.%
%:: SCCS/s.%

View file

@ -0,0 +1,9 @@
Installation from a directory on the filesystem.
The area you are installing from should contain the Packages.gz file
from each distribution area being installed (usually main and optionally
contrib, non-free-firmware 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.

124
dselect/methods/file/install.sh Executable file
View file

@ -0,0 +1,124 @@
#!/bin/sh
#
# 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
cd "$vardir/methods/file"
. ./shvar.$option
xit=1
trap '
exit $xit
' 0
predep="$vardir/predep-package"
while true; do
set +e
dpkg --admindir "$vardir" --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") or 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;
}
die "internal error - no package" if length($package) == 0;
die "internal error - no filename" if not @filename;
die "internal error - mismatch >@filename< >@msdosfilename<"
if @filename && @msdosfilename &&
@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,.*/,,;
$c = open(X, "-|"));
if (not defined $c) {
die "failed to fork for find: $!\n";
}
if (!$c) {
exec("find", "-L",
length($binaryprefix) ?
$binaryprefix : ".",
"-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)) {
warn "
Cannot find the appropriate file(s) anywhere needed to install or upgrade
package $package. Expecting version $version or later, as listed in the
Packages file.
Perhaps the package was downloaded with an unexpected name? 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 $vardir/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","--admindir",$vardir,"-iB","--",@invoke);
die "failed to exec dpkg: $!\n";
' -- "$p_mountpoint$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 --admindir $vardir -iGROEB "$p_mountpoint$this_binary"
dpkg --admindir $vardir -iGROEB "$p_mountpoint$this_binary"
done
echo -n 'Installation OK. Hit RETURN. '
read response
xit=0

View file

@ -0,0 +1 @@
42 file Install from a directory in the filesystem.

308
dselect/methods/file/setup.sh Executable file
View file

@ -0,0 +1,308 @@
#!/bin/sh
#
# 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
cd "$vardir/methods/file"
tp="$(mktemp --tmpdir $method.XXXXXXXXXX)"
iarch=$(dpkg --admindir $vardir --print-architecture)
xit=1
trap '
rm -f $tp.?
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
}
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 for ONE distribution.
# eg /pub/debian/dists/stable
# 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.
# fstype
# The filesystem type to use.
if [ -f shvar.$option ]; then
. ./shvar.$option
fi
if [ -n "$mountpoint" ]; then
# We must have $mountpoint
echo \
"All directory names should be entered relative to the root of the
$fstype filesystem.
"
fi
while true; do
echo \
"In order to make it easy to find the relevant files, it is preferred
to install from a straightforward copy of the Debian distribution.
To use this, it is required to know where the top level of that copy of
the distribution is (eg. 'debian/dists/stable') - this directory usually
contains the Packages-Master file.
If you do not have a straightforward copy of the distribution available
just answer 'none' and each needed part will be prompted individually."
defhierbase=none
# maybe ask for debian/dists and then show and ask for available dists
# eg. {stable,frozen,unstable,bo,hamm,slink}
if [ -n "$p_hierbase" ]; then
if [ -d "$mountpoint/$p_hierbase/main/binary-$iarch" ]; 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/main/binary-$iarch' doesn't seem to exist."
fi
fi
if [ none = "$defhierbase" ]; then
if [ -d "$mountpoint/debian/dists/stable/main/binary-$iarch" ]; then
echo "
'/debian/dists/stable' exists and looks plausible, so that's the default."
defhierbase=/debian/dists/stable
elif [ -d "$mountpoint/dists/stable/main/binary-$iarch" ]; then
echo "
'/dists/stable' exists and looks plausible, so that's the default."
defhierbase=/dists/stable
fi
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/main/binary-$iarch" ]; then
hierbase="$(echo "$response" | sed -e 's:/*$::; s:^/*:/:')"
break
fi
echo \
"$response/main/binary-$iarch does not exist.
"
done
case "$hierbase" in
/* )
;;
'' )
;;
* )
hierbase="/$hierbase"
;;
esac
check_binary () {
# args: area-in-messages directory
# eg: main "$hierbase/main/binary-$iarch"
# checks whether $2 contains *.deb
if ! [ -d "$mountpoint$2/" ]; then
echo "'$2' does not exist."
return
fi
if ! ( find -L "$mountpoint$2/" -name '*.deb' -print \
| head -n 1 ) 2>/dev/null | 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
# eg: main main main
# "$p_main_binary" "$p_main_packages"
this_binary=''
this_packages=''
if [ -n "$hierbase" ]; then
check_binary $1 "$hierbase/$3/binary-$iarch"
fi
if [ $2 = lcl ] && [ -z "$this_binary" ]; then
echo "
Note: By default there is no 'local' directory. It is intended for
packages you made yourself."
fi
if [ $2 = nf -a -z "$this_binary" ]; then
echo "
Note: most media distributions of Debian do not include programs available
in the 'non-free' directory of the distribution site.
This is because these programs are under licenses that do not allow source
modification or prevent distribution for profit on a media, or other
restrictions that make them not free software.
If you wish to install these programs you will 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-$iarch' on the distribution site) ?
Say 'none' if this area is not available."
if [ $2 != main ] && [ -z "$defaultbinary" ]; then
defaultbinary=none
fi
echo -n \
"Enter _$1_ binary dir. [$4]
? "
read response
if [ -z "$response" ] && [ -n "$defaultbinary" ]; then
response="$defaultbinary"
fi
if [ none = "$response" ]; 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 "
Cannot 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-$iarch' subdirectory of each area on the FTP sites and
media discs. Alternatively (and this will be rather slow) the packages in
the distribution area can be scanned - say 'scan' if you want to do so.
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" ] && [ -n "$5" ]; then
response="$5"
fi
case "$response" in
'')
continue
;;
none)
break
;;
scan)
this_packages=scan
;;
/*)
this_packages="$response"
;;
*)
this_packages="/$response"
;;
esac
done
fi
eval $2'_binary="$this_binary"'
eval $2'_packages="$this_packages"'
}
find_area main main main "$p_main_binary" "$p_main_packages"
find_area contrib ctb contrib "$p_ctb_binary" "$p_ctb_packages"
find_area non-free-firmware nff non-free-firmware "$p_nff_binary" "$p_nff_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_fstype "$fstype"
outputparam p_mountpoint "$mountpoint"
outputparam p_hierbase "$hierbase"
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_nff_packages "$nff_packages"
outputparam p_nff_binary "$nff_binary"
outputparam p_lcl_packages "$lcl_packages"
outputparam p_lcl_binary "$lcl_binary"
mv shvar.$option.new shvar.$option
xit=0

84
dselect/methods/file/update.sh Executable file
View file

@ -0,0 +1,84 @@
#!/bin/sh
#
# 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
cd "$vardir/methods/file"
. ./shvar.$option
if [ -z "$p_main_packages" ] && [ -z "$p_ctb_packages" ] && \
[ -z "$p_nf_packages" ] && [ -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 packages-ctb packages-nf packages-lcl
exit $xit
' 0
updatetype=update
for f in main ctb nf lcl; do
eval 'this_packages=$p_'$f'_packages'
case "$this_packages" in
'')
continue
;;
scan)
eval 'this_binary=$p_'$f'_binary'
if [ -z "$this_binary" ]; then
continue
fi
if [ "$updatetype" = update ]; then
dpkg --admindir $vardir --clear-avail
updatetype=merge
fi
echo Running dpkg --record-avail -R "$p_mountpoint$this_binary"
dpkg --admindir $vardir --record-avail -R "$p_mountpoint$this_binary"
;;
*)
packagesfile="$p_mountpoint$this_packages"
case "$packagesfile" in
*.gz)
echo -n "Uncompressing $packagesfile ... "
zcat <"$packagesfile" >packages-$f
echo done.
dpkg --admindir $vardir --$updatetype-avail packages-$f
updatetype=merge
;;
'')
;;
*)
dpkg --admindir $vardir --$updatetype-avail "$packagesfile"
updatetype=merge
;;
esac
;;
esac
done
echo -n 'Update OK. Hit RETURN. '
read response
xit=0

View file

@ -0,0 +1,2 @@
Installation using ftp, you must know one (or more) ftp site(s) and the
correct directories for the Debian distribution.

622
dselect/methods/ftp/install.pl Executable file
View file

@ -0,0 +1,622 @@
#!/usr/bin/perl
#
# Copyright © 1996 Andy Guy <andy@cyteen.org>
# Copyright © 1998 Martin Schulze <joey@infodrom.north.de>
# Copyright © 1999, 2009 Raphaël Hertzog <hertzog@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
use strict;
use warnings;
use File::Path qw(make_path remove_tree);
use File::Basename;
eval q{
use File::Find;
use Data::Dumper;
use Dpkg::File;
};
if ($@) {
warn "Missing Dpkg modules required by the FTP access method.\n\n";
exit 1;
}
use Dselect::Method;
use Dselect::Method::Ftp;
my $ftp;
# exit value
my $exit = 0;
# deal with arguments
my $vardir = $ARGV[0];
my $method = $ARGV[1];
my $option = $ARGV[2];
if ($option eq 'manual') {
print "manual mode not supported yet\n";
exit 1;
}
#print "vardir: $vardir, method: $method, option: $option\n";
my $methdir = "$vardir/methods/ftp";
# get info from control file
read_config("$methdir/vars");
chdir "$methdir";
make_path("$methdir/$CONFIG{dldir}", { mode => 0755 });
#Read md5sums already calculated
my %md5sums;
if (-f "$methdir/md5sums") {
my $code = file_slurp("$methdir/md5sums");
my $VAR1; ## no critic (Variables::ProhibitUnusedVariables)
my $res = eval $code;
if ($@) {
die "couldn't eval $methdir/md5sums content: $@\n";
}
if (ref($res)) { %md5sums = %{$res} }
}
# Get a stanza.
# returns a ref to a hash containing flds->fld contents
# white space from the ends of lines is removed and newlines added
# (no trailing newline).
# die's if something unexpected happens
sub get_stanza {
my $fh = shift;
my %flds;
my $fld;
while (<$fh>) {
if (length != 0) {
FLDLOOP: while (1) {
if ( /^(\S+):\s*(.*)\s*$/ ) {
$fld = lc($1);
$flds{$fld} = $2;
while (<$fh>) {
if (length == 0) {
return %flds;
} elsif ( /^(\s.*)$/ ) {
$flds{$fld} = $flds{$fld} . "\n" . $1;
} else {
next FLDLOOP;
}
}
return %flds;
} else {
die "expected a start of field line, but got:\n$_";
}
}
}
}
return %flds;
}
# process status file
# create curpkgs hash with version (no version implies not currently installed)
# of packages we want
print "Processing status file...\n";
my %curpkgs;
sub procstatus {
my (%flds, $fld);
open(my $status_fh, '<', "$vardir/status") or
die 'Could not open status file';
while (%flds = get_stanza($status_fh), %flds) {
if($flds{'status'} =~ /^install ok/) {
my $cs = (split(/ /, $flds{'status'}))[2];
if (($cs eq 'not-installed') ||
($cs eq 'half-installed') ||
($cs eq 'config-files')) {
$curpkgs{$flds{'package'}} = '';
} else {
$curpkgs{$flds{'package'}} = $flds{'version'};
}
}
}
close($status_fh);
}
procstatus();
sub dcmpvers {
my($a, $p, $b) = @_;
my ($r);
$r = system('dpkg', '--compare-versions', "$a", "$p", "$b");
$r = $r/256;
if ($r == 0) {
return 1;
} elsif ($r == 1) {
return 0;
}
die "dpkg --compare-versions $a $p $b - failed with $r";
}
# process package files, looking for packages to install
# create a hash of these packages pkgname => version, filenames...
# filename => md5sum, size
# for all packages
my %pkgs;
my %pkgfiles;
sub procpkgfile {
my $fn = shift;
my $site = shift;
my $dist = shift;
my (@files, @sizes, @md5sums, $pkg, $ver, $nfs, $fld);
my(%flds);
open(my $pkgfile_fh, '<', $fn) or die "could not open package file $fn";
while (%flds = get_stanza($pkgfile_fh), %flds) {
$pkg = $flds{'package'};
$ver = $curpkgs{$pkg};
@files = split(/[\s\n]+/, $flds{'filename'});
@sizes = split(/[\s\n]+/, $flds{'size'});
@md5sums = split(/[\s\n]+/, $flds{'md5sum'});
if (defined($ver) && (($ver eq '') || dcmpvers($ver, 'lt', $flds{'version'}))) {
$pkgs{$pkg} = [ $flds{'version'}, [ @files ], $site ];
$curpkgs{$pkg} = $flds{'version'};
}
$nfs = scalar(@files);
if(($nfs != scalar(@sizes)) || ($nfs != scalar(@md5sums)) ) {
print "Different number of filenames, sizes and md5sums for $flds{'package'}\n";
} else {
my $i = 0;
foreach my $fl (@files) {
$pkgfiles{$fl} = [ $md5sums[$i], $sizes[$i], $site, $dist ];
$i++;
}
}
}
close $pkgfile_fh or die "cannot close package file $fn: $!\n";
}
print "\nProcessing Package files...\n";
my ($i, $j);
$i = 0;
foreach my $site (@{$CONFIG{site}}) {
$j = 0;
foreach my $dist (@{$site->[2]}) {
my $fn = $dist;
$fn =~ tr#/#_#;
$fn = "Packages.$site->[0].$fn";
if (-f $fn) {
print " $site->[0] $dist...\n";
procpkgfile($fn,$i,$j);
} else {
print "Could not find packages file for $site->[0] $dist distribution (re-run Update)\n"
}
$j++;
}
$i++;
}
my $dldir = $CONFIG{dldir};
# md5sum
sub md5sum {
my $fn = shift;
my $m = qx(md5sum $fn);
$m = (split(' ', $m))[0];
$md5sums{"$dldir/$fn"} = $m;
return $m;
}
# construct list of files to get
# hash of filenames => size of downloaded part
# query user for each partial file
print "\nConstructing list of files to get...\n";
my %downloads;
my ($dir, @info, @files, $csize, $size);
my $totsize = 0;
foreach my $pkg (keys(%pkgs)) {
@files = @{$pkgs{$pkg}[1]};
foreach my $fn (@files) {
#Look for a partial file
if (-f "$dldir/$fn.partial") {
rename "$dldir/$fn.partial", "$dldir/$fn";
}
$dir = dirname($fn);
if(! -d "$dldir/$dir") {
make_path("$dldir/$dir", { mode => 0755 });
}
@info = @{$pkgfiles{$fn}};
$csize = int($info[1]/1024)+1;
if(-f "$dldir/$fn") {
$size = -s "$dldir/$fn";
if($info[1] > $size) {
# partial download
if (yesno('y', "continue file: $fn (" . nb($size) . '/' .
nb($info[1]) . ')')) {
$downloads{$fn} = $size;
$totsize += $csize - int($size/1024);
} else {
$downloads{$fn} = 0;
$totsize += $csize;
}
} else {
# check md5sum
if (! exists $md5sums{"$dldir/$fn"}) {
$md5sums{"$dldir/$fn"} = md5sum("$dldir/$fn");
}
if ($md5sums{"$dldir/$fn"} eq $info[0]) {
print "already got: $fn\n";
} else {
print "corrupted: $fn\n";
$downloads{$fn} = 0;
}
}
} else {
my $ffn = $fn;
$ffn =~ s/binary-[^\/]+/.../;
print 'want: ' .
$CONFIG{site}[$pkgfiles{$fn}[2]][0] . " $ffn (${csize}k)\n";
$downloads{$fn} = 0;
$totsize += $csize;
}
}
}
my $avsp = qx(df -Pk $dldir| awk '{ print \$4}' | tail -n 1);
chomp $avsp;
print "\nApproximate total space required: ${totsize}k\n";
print "Available space in $dldir: ${avsp}k\n";
#$avsp = qx(df -k $::dldir| paste -s | awk '{ print \$11});
#chomp $avsp;
if($totsize == 0) {
print 'Nothing to get.';
} else {
if($totsize > $avsp) {
print "Space required is greater than available space,\n";
print "you will need to select which items to get.\n";
}
# ask user which files to get
if (($totsize > $avsp) ||
yesno('n', 'Do you want to select the files to get')) {
$totsize = 0;
my @files = sort(keys(%downloads));
my $def = 'y';
foreach my $fn (@files) {
my @info = @{$pkgfiles{$fn}};
my $csize = int($info[1] / 1024) + 1;
my $rsize = int(($info[1] - $downloads{$fn}) / 1024) + 1;
if ($rsize + $totsize > $avsp) {
print "no room for: $fn\n";
delete $downloads{$fn};
} elsif (yesno($def, $downloads{$fn}
? "download: $fn ${rsize}k/${csize}k (total = ${totsize}k)"
: "download: $fn ${rsize}k (total = ${totsize}k)")) {
$def = 'y';
$totsize += $rsize;
} else {
$def = 'n';
delete $downloads{$fn};
}
}
}
}
sub download {
my $i = 0;
foreach my $site (@{$CONFIG{site}}) {
my @getfiles = grep { $pkgfiles{$_}[2] == $i } keys %downloads;
my @pre_dist = (); # Directory to add before $fn
#Scan distributions for looking at "(../)+/dir/dir"
my ($n,$cp);
$cp = -1;
foreach (@{$site->[2]}) {
$cp++;
$pre_dist[$cp] = '';
$n = (s{\.\./}{../}g);
next if (! $n);
if (m<^((?:\.\./){$n}(?:[^/]+/){$n})>) {
$pre_dist[$cp] = $1;
}
}
if (! @getfiles) { $i++; next; }
$ftp = do_connect(ftpsite => $site->[0],
ftpdir => $site->[1],
passive => $site->[3],
username => $site->[4],
password => $site->[5],
useproxy => $CONFIG{use_auth_proxy},
proxyhost => $CONFIG{proxyhost},
proxylogname => $CONFIG{proxylogname},
proxypassword => $CONFIG{proxypassword});
local $SIG{INT} = sub { die "Interrupted !\n"; };
my ($rsize, $res, $pre);
foreach my $fn (@getfiles) {
$pre = $pre_dist[$pkgfiles{$fn}[3]] || '';
if ($downloads{$fn}) {
$rsize = ${pkgfiles{$fn}}[1] - $downloads{$fn};
print "getting: $pre$fn (" . nb($rsize) . '/' .
nb($pkgfiles{$fn}[1]) . ")\n";
} else {
print "getting: $pre$fn (". nb($pkgfiles{$fn}[1]) . ")\n";
}
$res = $ftp->get("$pre$fn", "$dldir/$fn", $downloads{$fn});
if(! $res) {
my $r = $ftp->code();
print $ftp->message() . "\n";
if (!($r == 550 || $r == 450)) {
return 1;
} else {
#Try to find another file or this package
print "Looking for another version of the package...\n";
my ($dir, $package) = ($fn =~ m{^(.*)/([^/]+)_[^/]+.deb$});
my $list = $ftp->ls("$pre$dir");
if ($ftp->ok() && ref($list)) {
foreach my $file (@{$list}) {
if ($file =~ m/($dir\/\Q$package\E_[^\/]+.deb)/i) {
print "Package found : $file\n";
print "getting: $file (size not known)\n";
$res = $ftp->get($file, "$dldir/$1");
if (! $res) {
$r = $ftp->code();
print $ftp->message() . "\n";
return 1 if ($r != 550 and $r != 450);
}
}
}
}
}
}
# fully got, remove it from list in case we have to re-download
delete $downloads{$fn};
}
$ftp->quit();
$i++;
}
return 0;
}
# download stuff (protect from ^C)
if($totsize != 0) {
if (yesno('y', "\nDo you want to download the required files")) {
DOWNLOAD_TRY: while (1) {
print "Downloading files... use ^C to stop\n";
eval {
if ((download() == 1) &&
yesno('y', "\nDo you want to retry downloading at once")) {
next DOWNLOAD_TRY;
}
};
if($@ =~ /Interrupted|Timeout/i ) {
# close the FTP connection if needed
if ((ref($ftp) =~ /Net::FTP/) and ($@ =~ /Interrupted/i)) {
$ftp->abort();
$ftp->quit();
undef $ftp;
}
print "FTP ERROR\n";
if (yesno('y', "\nDo you want to retry downloading at once")) {
# get the first $fn that foreach would give:
# this is the one that got interrupted.
my $fn;
MY_ITER: foreach my $ffn (keys(%downloads)) {
$fn = $ffn;
last MY_ITER;
}
my $size = -s "$dldir/$fn";
# partial download
if (yesno('y', "continue file: $fn (at $size)")) {
$downloads{$fn} = $size;
} else {
$downloads{$fn} = 0;
}
next DOWNLOAD_TRY;
} else {
$exit = 1;
last DOWNLOAD_TRY;
}
} elsif ($@) {
print "An error occurred ($@) : stopping download\n";
}
last DOWNLOAD_TRY;
}
}
}
# remove duplicate packages (keep latest versions)
# move half downloaded files out of the way
# delete corrupted files
print "\nProcessing downloaded files...(for corrupt/old/partial)\n";
my %vers; # package => version
my %files; # package-version => files...
# check a deb or split deb file
# return 1 if it a deb file, 2 if it is a split deb file
# else 0
sub chkdeb {
my ($fn) = @_;
# check to see if it is a .deb file
if (!system "dpkg-deb --info $fn >/dev/null 2>&1 && dpkg-deb --contents $fn >/dev/null 2>&1") {
return 1;
} elsif (!system "dpkg-split --info $fn >/dev/null 2>&1") {
return 2;
}
return 0;
}
sub getdebinfo {
my ($fn) = @_;
my $type = chkdeb($fn);
my ($pkg, $ver);
if($type == 1) {
open(my $pkgfile_fh, '-|', "dpkg-deb --field $fn")
or die "cannot create pipe for 'dpkg-deb --field $fn'";
my %fields = get_stanza($pkgfile_fh);
close($pkgfile_fh);
$pkg = $fields{'package'};
$ver = $fields{'version'};
return $pkg, $ver;
} elsif ( $type == 2) {
open(my $pkgfile_fh, '-|', "dpkg-split --info $fn")
or die "cannot create pipe for 'dpkg-split --info $fn'";
while (<$pkgfile_fh>) {
/Part of package:\s*(\S+)/ and $pkg = $1;
/\.\.\. version:\s*(\S+)/ and $ver = $1;
}
close($pkgfile_fh);
return $pkg, $ver;
}
print "could not figure out type of $fn\n";
return $pkg, $ver;
}
# process deb file to make sure we only keep latest versions
sub prcdeb {
my ($dir, $fn) = @_;
my ($pkg, $ver) = getdebinfo($fn);
if(!defined($pkg) || !defined($ver)) {
print "could not get package info from file\n";
return 0;
}
if($vers{$pkg}) {
if (dcmpvers($vers{$pkg}, 'eq', $ver)) {
$files{$pkg . $ver} = [ $files{$pkg . $ver }, "$dir/$fn" ];
} elsif (dcmpvers($vers{$pkg}, 'gt', $ver)) {
print "old version\n";
unlink $fn;
} else { # else $ver is gt current version
foreach my $c (@{$files{$pkg . $vers{$pkg}}}) {
print "replaces: $c\n";
unlink "$vardir/methods/ftp/$dldir/$c";
}
$vers{$pkg} = $ver;
$files{$pkg . $ver} = [ "$dir/$fn" ];
}
} else {
$vers{$pkg} = $ver;
$files{$pkg . $ver} = [ "$dir/$fn" ];
}
}
sub prcfile {
my ($fn) = $_;
if (-f $fn and $fn ne '.') {
my $dir = '.';
if (length($File::Find::dir) > length($dldir)) {
$dir = substr($File::Find::dir, length($dldir)+1);
}
print "$dir/$fn\n";
if(defined($pkgfiles{"$dir/$fn"})) {
my @info = @{$pkgfiles{"$dir/$fn"}};
my $size = -s $fn;
if($size == 0) {
print "zero length file\n";
unlink $fn;
} elsif($size < $info[1]) {
print "partial file\n";
rename $fn, "$fn.partial";
} elsif(( (exists $md5sums{"$dldir/$fn"})
and ($md5sums{"$dldir/$fn"} ne $info[0]) )
or
(md5sum($fn) ne $info[0])) {
print "corrupt file\n";
unlink $fn;
} else {
prcdeb($dir, $fn);
}
} elsif($fn =~ /.deb$/) {
if(chkdeb($fn)) {
prcdeb($dir, $fn);
} else {
print "corrupt file\n";
unlink $fn;
}
} else {
print "non-debian file\n";
}
}
}
find(\&prcfile, "$dldir/");
# install .debs
if (yesno('y', "\nDo you want to install the files fetched")) {
print "Installing files...\n";
#Installing pre-dependent package before !
my (@flds, $package, @filename, $r);
while (@flds = qx(dpkg --predep-package), $? == 0) {
foreach my $field (@flds) {
$field =~ s/\s*\n//;
$package = $field if $field =~ s/^Package: //i;
@filename = split / +/, $field if $field =~ s/^Filename: //i;
}
@filename = map { "$dldir/$_" } @filename;
next if (! @filename);
$r = system('dpkg', '-iB', '--', @filename);
if ($r) { print "DPKG ERROR\n"; $exit = 1; }
}
#Installing other packages after
$r = system('dpkg', '-iGREOB', $dldir);
if($r) {
print "DPKG ERROR\n";
$exit = 1;
}
}
sub removeinstalled {
my $fn = $_;
if (-f $fn and $fn ne '.') {
my $dir = '.';
if (length($File::Find::dir) > length($dldir)) {
$dir = substr($File::Find::dir, length($dldir)+1);
}
if($fn =~ /.deb$/) {
my($pkg, $ver) = getdebinfo($fn);
if(!defined($pkg) || !defined($ver)) {
print "Could not get info for: $dir/$fn\n";
} elsif ($curpkgs{$pkg} and dcmpvers($ver, 'le', $curpkgs{$pkg})) {
print "deleting: $dir/$fn\n";
unlink $fn;
} else {
print "leaving: $dir/$fn\n";
}
} else {
print "non-debian: $dir/$fn\n";
}
}
}
# remove .debs that have been installed (query user)
# first need to reprocess status file
if (yesno('y', "\nDo you wish to delete the installed package (.deb) files?")) {
print "Removing installed files...\n";
%curpkgs = ();
procstatus();
find(\&removeinstalled, "$dldir/");
}
# remove whole ./debian directory if user wants to
if (yesno('n', "\nDo you want to remove $dldir directory?")) {
remove_tree($dldir);
}
#Store useful md5sums
foreach my $file (keys %md5sums) {
next if -f $file;
delete $md5sums{$file};
}
file_dump("$methdir/md5sums", Dumper(\%md5sums));
exit $exit;

View file

@ -0,0 +1 @@
60 ftp Install using ftp.

177
dselect/methods/ftp/setup.pl Executable file
View file

@ -0,0 +1,177 @@
#!/usr/bin/perl
#
# Copyright © 1996 Andy Guy <andy@cyteen.org>
# Copyright © 1998 Martin Schulze <joey@infodrom.north.de>
# Copyright © 1999, 2009 Raphaël Hertzog <hertzog@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
use strict;
use warnings;
eval q{
use Dpkg; # Dummy import to require the presence of Dpkg::*.
};
if ($@) {
warn "Missing Dpkg modules required by the FTP access method.\n\n";
exit 1;
}
use Dselect::Method;
use Dselect::Method::Ftp;
# deal with arguments
my $vardir = $ARGV[0];
my $method = $ARGV[1];
my $option = $ARGV[2];
if ($option eq 'manual') {
print "Manual package installation.\n";
exit 0;
}
#print "vardir: $vardir, method: $method, option: $option\n";
#Defaults
my $arch = qx(dpkg --print-architecture);
$arch = 'i386' if $?;
chomp $arch;
my $logname = qx(whoami);
chomp $logname;
my $host = qx(cat /etc/mailname || dnsdomainname);
chomp $host;
$CONFIG{dldir} = 'debian';
$CONFIG{use_auth_proxy} = 0;
$CONFIG{proxyhost} = '';
$CONFIG{proxylogname} = $logname;
$CONFIG{proxypassword} = '';
my $methdir = "$vardir/methods/ftp";
my $exit = 0;
my $problem = 0;
if (-f "$methdir/vars") {
read_config("$methdir/vars");
}
chdir "$methdir";
if (! -d 'debian') {
mkdir 'debian', 0755;
}
# get info from user
$| = 1;
print <<"EOM";
You must supply an ftp site, use of passive mode, username, password,
path to the debian directory,list of distributions you are interested
in and place to download the binary package files to (relative to
/var/lib/dpkg/methods/ftp). You can add as much sites as you like. Later
entries will always override older ones.
Supply "?" as a password to be asked each time you connect.
Eg: ftp site: ftp.debian.org
passive: y
username: anonymous
password: $logname\@$host
ftp dir: /debian
distributions: dists/stable/main dists/stable/contrib
download dir: debian
You may have to use an authenticated FTP proxy in order to reach the
FTP site:
Eg: use auth proxy: y
proxy: proxy.isp.com
proxy account: $CONFIG{proxylogname}
proxy password: ?
EOM
if (! $CONFIG{done}) {
view_mirrors() if (yesno('y', 'Would you like to see a list of ftp mirrors'));
add_site('ftp');
}
edit_config('ftp', $methdir);
my $ftp;
sub download {
foreach (@{$CONFIG{site}}) {
$ftp = do_connect(ftpsite => $_->[0],
ftpdir => $_->[1],
passive => $_->[3],
username => $_->[4],
password => $_->[5],
useproxy => $CONFIG{use_auth_proxy},
proxyhost => $CONFIG{proxyhost},
proxylogname => $CONFIG{proxylogname},
proxypassword => $CONFIG{proxypassword});
my @dists = @{$_->[2]};
foreach my $dist (@dists) {
my $dir = "$dist/binary-$arch";
print "Checking $dir...\n";
# if (!$ftp->pasv()) { print $ftp->message . "\n"; die 'error'; }
my @dirlst = $ftp->ls("$dir/");
my $got_pkgfile = 0;
foreach my $line (@dirlst) {
if($line =~ /Packages/) {
$got_pkgfile = 1;
}
}
if( !$got_pkgfile) {
print "warning: could not find a Packages file in $dir\n",
"This may not be a problem if the directory is a symbolic link\n";
$problem = 1;
}
}
print "Closing ftp connection...\n";
$ftp->quit();
}
}
# download stuff (protect from ^C)
print "\nUsing FTP to check directories...(stop with ^C)\n\n";
eval {
local $SIG{INT} = sub {
die "interrupted!\n";
};
download();
};
if($@) {
$ftp->quit();
print 'FTP ERROR - ';
if ($@ eq 'connect') {
print "config was untested\n";
} else {
print "$@\n";
}
$exit = 1;
};
# output new vars file
$CONFIG{done} = 1;
store_config("$methdir/vars");
chmod 0600, "$methdir/vars";
if($exit || $problem) {
print "Press <enter> to continue\n";
<STDIN>;
}
exit $exit;

250
dselect/methods/ftp/update.pl Executable file
View file

@ -0,0 +1,250 @@
#!/usr/bin/perl
#
# Copyright © 1996 Andy Guy <andy@cyteen.org>
# Copyright © 1998 Martin Schulze <joey@infodrom.north.de>
# Copyright © 1999, 2009 Raphaël Hertzog <hertzog@debian.org>
#
# 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, see <https://www.gnu.org/licenses/>.
use strict;
use warnings;
eval q{
use Dpkg; # Dummy import to require the presence of Dpkg::*.
};
if ($@) {
warn "Missing Dpkg modules required by the FTP access method.\n\n";
exit 1;
}
use Dselect::Method;
use Dselect::Method::Ftp;
# deal with arguments
my $vardir = $ARGV[0];
my $method = $ARGV[1];
my $option = $ARGV[2];
if ($option eq 'manual') {
print "Enter package file names or a blank line to finish\n";
while(1) {
print 'Enter package file name:';
my $fn = <STDIN>;
chomp $fn;
if ($fn eq '') {
exit 0;
}
if ( -f $fn ) {
system('dpkg', '--merge-avail', $fn);
} else {
print "Could not find $fn, try again\n";
}
};
};
#print "vardir: $vardir, method: $method, option: $option\n";
my $arch = qx(dpkg --print-architecture);
$arch = 'i386' if $?;
chomp $arch;
my $exit = 0;
# get info from control file
read_config("$vardir/methods/ftp/vars");
chdir "$vardir/methods/ftp";
print "Getting Packages files...(stop with ^C)\n\n";
my @pkgfiles;
my $ftp;
my $packages_modified = 0;
sub download {
foreach (@{$CONFIG{site}}) {
my $site = $_;
$ftp = do_connect(ftpsite => $_->[0],
ftpdir => $_->[1],
passive => $_->[3],
username => $_->[4],
password => $_->[5],
useproxy => $CONFIG{use_auth_proxy},
proxyhost => $CONFIG{proxyhost},
proxylogname => $CONFIG{proxylogname},
proxypassword => $CONFIG{proxypassword});
my @dists = @{$_->[2]};
PACKAGE:
foreach my $dist (@dists) {
my $dir = "$dist/binary-$arch";
my $must_get = 0;
my $newest_pack_date;
# check existing Packages on remote site
print "\nChecking for Packages file... ";
$newest_pack_date = do_mdtm ($ftp, "$dir/Packages.gz");
if (defined $newest_pack_date) {
print "$dir/Packages.gz\n";
} else {
$dir = "$dist";
$newest_pack_date = do_mdtm ($ftp, "$dir/Packages.gz");
if (defined $newest_pack_date) {
print "$dir/Packages.gz\n";
} else {
print "Couldn't find Packages.gz in $dist/binary-$arch or $dist; ignoring.\n";
print "Your setup is probably wrong, check the distributions directories,\n";
print "and try with passive mode enabled/disabled (if you use a proxy/firewall)\n";
next PACKAGE;
}
}
# we now have $dir set to point to an existing Packages.gz file
# check if we already have a Packages file (and get its date)
$dist =~ tr/\//_/;
my $file = "Packages.$site->[0].$dist";
# if not
if (! -f $file) {
# must get one
# print "No Packages here; must get it.\n";
$must_get = 1;
} else {
# else check last modification date
my @pack_stat = stat($file);
if($newest_pack_date > $pack_stat[9]) {
# print "Packages has changed; must get it.\n";
$must_get = 1;
} elsif ($newest_pack_date < $pack_stat[9]) {
print " Our file is newer than theirs; skipping.\n";
} else {
print " Already up-to-date; skipping.\n";
}
}
if ($must_get) {
-f 'Packages.gz' and unlink 'Packages.gz';
-f 'Packages' and unlink 'Packages';
my $size = 0;
TRY_GET_PACKAGES:
while (1) {
if ($size) {
print ' Continuing ';
} else {
print ' Getting ';
}
print "Packages file from $dir...\n";
eval {
if ($ftp->get("$dir/Packages.gz", 'Packages.gz', $size)) {
if (system('gunzip', 'Packages.gz')) {
print " Couldn't gunzip Packages.gz, stopped";
die 'error';
}
} else {
print " Couldn't get Packages.gz from $dir !!! Stopped.";
die 'error';
}
};
if ($@) {
$size = -s 'Packages.gz';
if (ref($ftp)) {
$ftp->abort();
$ftp->quit();
};
if (yesno ('y', "Transfer failed at $size: retry at once")) {
$ftp = do_connect(ftpsite => $site->[0],
ftpdir => $site->[1],
passive => $site->[3],
username => $site->[4],
password => $site->[5],
useproxy => $CONFIG{use_auth_proxy},
proxyhost => $CONFIG{proxyhost},
proxylogname => $CONFIG{proxylogname},
proxypassword => $CONFIG{proxypassword});
if ($newest_pack_date != do_mdtm ($ftp, "$dir/Packages.gz")) {
print ("Packages file has changed !\n");
$size = 0;
}
next TRY_GET_PACKAGES;
} else {
die 'error';
}
}
last TRY_GET_PACKAGES;
}
if (!rename 'Packages', "Packages.$site->[0].$dist") {
print " Couldn't rename Packages to Packages.$site->[0].$dist";
die 'error';
} else {
# set local Packages file to same date as the one it mirrors
# to allow comparison to work.
utime $newest_pack_date, $newest_pack_date, "Packages.$site->[0].$dist";
$packages_modified = 1;
}
}
push @pkgfiles, "Packages.$site->[0].$dist";
}
$ftp->quit();
}
}
eval {
local $SIG{INT} = sub {
die "interrupted!\n";
};
download();
};
if($@) {
$ftp->quit() if (ref($ftp));
if($@ =~ /timeout/i) {
print "FTP TIMEOUT\n";
} else {
print "FTP ERROR - $@\n";
}
$exit = 1;
};
# Don't clear if nothing changed.
if ($packages_modified) {
print <<'EOM';
It is a good idea to clear the available list of old packages.
However if you have only downloaded a Package files from non-main
distributions you might not want to do this.
EOM
if (yesno ('y', 'Do you want to clear available list')) {
print "Clearing...\n";
if (system('dpkg', '--clear-avail')) {
print 'dpkg --clear-avail failed.';
die 'error';
}
}
}
if (!$packages_modified) {
print "No Packages files was updated.\n";
} else {
foreach my $file (@pkgfiles) {
if (system('dpkg', '--merge-avail', $file)) {
print "Dpkg merge available failed on $file";
$exit = 1;
}
}
}
exit $exit;

View file

@ -0,0 +1,106 @@
Installation method for multiple binary media
---------------------------------------------
This directory contains a method to be used within dselect in order to
access Debian binary packages stored across multiple binary media
(CDs, DVDs, BDs, or USBs).
Acquiring package data
---------------------
It is possible to access the following binary directories within
«dists/stable»:
. main
. contrib
. non-free-firmware
. non-free
. local
The selected method will try to read the «Packages.cd» file from each
of these directories if it is available.
Identifying the media
----------------------
A unique name is associated to each media disc. This name should correspond
with the label on the front of the media disc. The name is also available on
the media disc, so the system can find out which media disc is inserted into
the computer at any time.
Installing the files
--------------------
At the beginning of the installation the “media” method will sort the list
of to-be-installed packages and install them media disc by media disc. If a
different media disc is required the user will be prompted to exchange
the media disc.
Preparing multiple binary media discs
-------------------------------------
Since the “media” method needs to know which packages are on which
media disc one cannot use regular «Packages» files. An additional data
field «X-Medium:» is required. The first media disc from the set should
contain all «Packages.cd» files. To be more convenient you should
include the «Packages.cd» files on all media discs. This ensures that
you do not have to start with the first media disc all the time.
Additionally the package needs to gain information which media disc is
currently used. Thus each media disc contains the file «.disk/info»
which contains the symbolic name for the media disc as specified by
«X-Medium:».
In order to be able to create the modified «Packages.cd» files, you
have to use the «-M medium» option of dpkg-scanpackages (supported
in dpkg-dev since 1.15.5).
To split the “main” distribution into two media discs you will need to
create a «Packages.cd» file for each «binary-$arch» directory.
Afterwards you simply append the second one to the first one and
put the resulting «Packages.cd» file into both «binary-$arch»
directories.
Sample Layout
-------------
Media disc 1 .disk/info = "Debian GNU/Linux binary-amd64"
dists/stable/main/binary-all/
binary-amd64/Packages.cd.gz
binary-amd64/net/foo.deb
contrib/binary-amd64/Packages.cd.gz
non-free-firmware/binary-amd64/Packages.cd.gz
non-free/binary-amd64/Packages.cd.gz
Media disc 2 .disk/info = "Debian GNU/Linux contrib-amd64"
dists/stable/main/binary-amd64/Packages.cd.gz
contrib/binary-all/
binary-amd64/Packages.cd.gz
binary-amd64/net/foo.deb
non-free-firmware/binary-amd64/Packages.cd.gz
non-free/binary-amd64/Packages.cd.gz
Media disc 3 .disk/info = "Debian GNU/Linux non-free-amd64"
dists/stable/main/binary-amd64/Packages.cd.gz
contrib/binary-amd64/Packages.cd.gz
non-free-firmware/binary-amd64/Packages.cd.gz
non-free/binary-all/
binary-amd64/Packages.cd.gz
binary-amd64/net/foo.deb
To re-generate the Packages file you have to change directory into
«dists/stable/$part» and issue «dpkg-scanpackages» as follows. It is
assumed that you use regular compressed overrides files in
«/pub/debian/indices».
Media disc 1: dpkg-scanpackages -M "Debian GNU/Linux binary-amd64" \
binary-amd64 /pub/debian/indices/override.buster.gz \
dists/stable/ > binary-amd64/Packages
Media disc 2: dpkg-scanpackages -M "Debian GNU/Linux contrib-amd64" \
binary-amd64 /pub/debian/indices/override.buster.contrib.gz \
dists/stable/ > binary-amd64/Packages
Media disc 3: dpkg-scanpackages -M "Debian GNU/Linux non-free-amd64" \
binary-amd64 /pub/debian/indices/override.buster.non-free.gz \
dists/stable/ > binary-amd64/Packages

View file

@ -0,0 +1,3 @@
Installation from a media set containing a Debian distribution. The
media discs may be or not be mounted already and should contain a standard
ISO9660 media filesystem.

282
dselect/methods/media/install.sh Executable file
View file

@ -0,0 +1,282 @@
#!/bin/sh
#
# Copyright © 1995-1998 Ian Jackson <ijackson@chiark.greenend.org.uk>
# Copyright © 1998 Heiko Schlittermann <hs@schlittermann.de>
#
# 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 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
cd "$vardir/methods/$method"
. ./shvar.$option
#debug() { echo "DEBUG: $@"; }
debug() {
true
}
iarch=$(dpkg --print-architecture)
# 1/ mountpoint
# 2/ hierarchy
getdisklabel () {
debug "$1" "$2"
if [ -f $1/.disk/info ]; then
echo -n $(head -1 "$1/.disk/info")
elif [ -f $1$2/.disk/info ]; then
echo -n $(head -1 "$1$2/.disk/info")
else
echo -n 'Non-Debian disc'
fi
}
xit=1
do_umount() {
if [ -n "$umount" ]; then
echo umount "$umount"
#">/dev/null" "2>&1"
fi
}
do_mount() {
if [ ! -b "$p_blockdev" ]; then
loop=",loop"
fi
if [ -n "$p_blockdev" ]; then
umount="$p_mountpoint"
echo mount -rt iso9660 -o nosuid,nodev${loop} "$p_blockdev" "$p_mountpoint"\; umount="$p_mountpoint"
fi
}
trap 'eval $(do_umount); exit $xit' 0
eval $(do_mount)
predep="$vardir/predep-package"
while true; do
thisdisk="$(getdisklabel ${p_mountpoint} ${p_hierbase})"
set +e
dpkg --predep-package >"$predep"
rc=$?
set -e
if test $rc = 1; then
break
fi
test $rc = 0
perl -e '
($binaryprefix,$predep,$thisdisk) = @ARGV;
open(P, "< $predep") or die "cannot open $predep: $!\n";
while (<P>) {
s/\s*\n$//;
$package = $_ if s/^Package: //i;
/^X-Medium:\s+(.*)\s*/ and $medium = $1;
@filename = split(/ /,$_) if s/^Filename: //i;
@msdosfilename = split(/ /,$_) if s/^MSDOS-Filename: //i;
}
die "internal error - no package" if length($package) == 0;
die "internal error - no filename" if not @filename;
die "internal error - mismatch >@filename< >@msdosfilename<"
if @filename && @msdosfilename &&
@filename != @msdosfilename;
if ($medium && ($medium ne $thisdisk)) {
print "
This is
$thisdisk
However, $package is expected on disc:
$medium
Please change the discs and press <RETURN>.
";
exit(1);
}
@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,.*/,,;
$c = open(X, "-|"));
if (not defined $c) {
die "failed to fork for find: $!\n";
}
if (!$c) {
exec("find", "-L",
length($binaryprefix) ? $binaryprefix : ".",
"-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)) {
warn "
Cannot find the appropriate file(s) anywhere needed to install or upgrade
package $package. Expecting version $version or later, as listed in the
Packages file.
Perhaps the package was downloaded with an unexpected name? 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 $vardir/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";
' -- "$p_mountpoint$p_hierbase" "$predep" "$thisdisk"
done
perl -e '
$SIG{INT} = sub { cd $vardir; unlink <tmp/*>; exit 1; };
$| = 1;
my ($vardir, $mountpoint, $hierbase, $mount, $umount) = @ARGV;
my $line;
my $AVAIL = "$vardir/methods/media/available";
my $STATUS = "$vardir/status";
my %Installed, %Filename, %Medium;
print "Get currently installed package versions...";
open(IN, "$STATUS") or die "cannot open $STATUS: $!\n";
$line = 0;
{ local $/ = "";
while (<IN>) {
my %status;
my @pstat;
$line++ % 20 or print ".";
s/\n\s+/ /g;
%status = ("", split /^(\S*?):\s*/m, $_);
map { chomp $status{$_}; $status{$_} =~ s/^\s*(.*?)\s*$/$1/;} keys %status;
@pstat = split(/ /, $status{Status});
next unless ($pstat[0] eq "install");
if ($pstat[2] eq "config-files" || $pstat[2] eq "not-installed") {
$Installed{$status{Package}} = "0.0";
} else {
$Installed{$status{Package}} = $status{Version} || "" ;
}
}; }
print "\nGot ", scalar keys %Installed, " installed/pending packages\n";
print "Scanning available packages...";
$line = 0;
open(IN, "$AVAIL") or die("Cannot open $AVAIL: $!\n");
{ local $/ = "";
while (<IN>) {
my $updated;
$line++ % 20 or print ".";
s/\n\s+/ /g;
%avail = ("", split /^(\S*?):\s*/m, $_);
map { chomp $avail{$_}; $avail{$_} =~ s/^\s*(.*?)\s*$/$1/;} keys %avail;
next unless defined $Installed{$avail{Package}};
system "dpkg", "--compare-versions", $avail{Version}, "gt", $Installed{$avail{Package}};
$updated = ($? == 0);
#print "$avail{Package}(" . ($updated ? "+" : "=") . ") ";
$updated or next;
$Filename{$avail{Package}} = $avail{Filename};
next unless defined $avail{"X-Medium"};
${Medium{$avail{"X-Medium"}}} or ${Medium{$avail{"X-Medium"}}} = [];
push @{${Medium{$avail{"X-Medium"}}}}, $avail{Package};
}; };
print "\n";
if (@_ = keys(%Medium)) {
print "You will need the following distribution disc(s):\n",
join (", ", @_), "\n";
}
foreach $need (sort @_) {
if (-r "$mountpoint/.disk/info") {
open(IN, "$mountpoint/.disk/info") or die("$mountpoint/.disk/info: $!\n");
} else {
open(IN, "$mountpoint/$hierbase/.disk/info") or die("$mountpoint/$hierbase/.disk/info: $!\n");
}
$disk = <IN>; chomp $disk; close(IN);
print "Processing disc\n $need\n";
while ($disk ne $need) {
print "Wrong disc. This is disc\n $disk\n";
print "However, the needed disc is\n $need\n";
print "Please change the discs and press <RETURN>\n";
system($umount);
<STDIN>;
system($mount);
$? and warn("cannot mount $mount\n");
} continue {
if (-r "$mountpoint/.disk/info") {
open(IN, "$mountpoint/.disk/info") or die("$mountpoint/.disk/info: $!\n");
} else {
open(IN, "$mountpoint/$hierbase/.disk/info") or die("$mountpoint/$hierbase/.disk/info: $!\n");
}
$disk = <IN>; chomp $disk; close(IN);
}
-d "tmp" || mkdir "tmp", 0755 or die("Cannot mkdir tmp: $!\n");
unlink <tmp/*>;
print "creating symlinks...\n";
foreach (@{$Medium{$need}}) {
($basename = $Filename{$_}) =~ s/.*\///;
symlink "$mountpoint/$hierbase/$Filename{$_}",
"tmp/$basename";
}
chdir "tmp" or die "cannot chdir to tmp: $!\n";
system "dpkg", "-iGROEB", ".";
unlink <*>;
chdir "..";
if ($?) {
print "\nThe dpkg run produced errors. Please state whether to\n",
"continue with the next media disc. [Y/n]: ";
$answer = <STDIN>;
exit 1 if $answer =~ /^n/i;
$ouch = $?;
}
}
exit $ouch;
' "$vardir" "$p_mountpoint" "$p_hierbase" "$(do_mount)" "$(do_umount)"
echo -n 'Installation OK. Hit RETURN. '
read response
xit=0

View file

@ -0,0 +1 @@
31 media Install from a media set (CDs, DVDs, BDs, USBs).

489
dselect/methods/media/setup.sh Executable file
View file

@ -0,0 +1,489 @@
#!/bin/sh
#
# Copyright © 1995-1998 Ian Jackson <ijackson@chiark.greenend.org.uk>
# Copyright © 1998 Heiko Schlittermann <hs@schlittermann.de>
# Copyright © 1998-1999 Martin Schulze <joey@infodrom.north.de>
#
# 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 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
test -d "$vardir/methods/$method" || mkdir "$vardir/methods/$method"
cd "$vardir/methods/$method"
tp="$(mktemp --tmpdir $method.XXXXXXXXXX)"
iarch=$(dpkg --print-architecture)
dist=stable
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
#debug() { echo "DEBUG: $@"; }
debug() {
true
}
ismulti() {
debug $1 $2; test -e "$1/.disk/info" || test -e "$1$2/.disk/info"
}
# 1/ mountpoint
# 2/ hierarchy
getdisklabel () {
debug "$1" "$2"
if [ -f $1/.disk/info ]; then
echo -n $(head -1 "$1/.disk/info")
elif [ -f $1$2/.disk/info ]; then
echo -n $(head -1 "$1$2/.disk/info")
else
echo -n 'Non-Debian disc'
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 - will try as loopback."
loop=",loop"
fi
tryblockdevice="$response"
fstype=iso9660
umount="$mountpoint"
if mount -rt "$fstype" -o nosuid,nodev$loop "$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
}
## MAIN
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"
usedevel="$p_usedevel"
fi
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 media discs (ISO9660 filesystems) are mounted:'
grep -E '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 \
"Found a media disc: $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 'Found that /dev/cdrom exists and is a block device.'
newdefaultdevice=/dev/cdrom
fi
getblockdev 'Insert the media and enter the block device name'
fi
if [ -n "$mountpoint" ]; then
# We must have $mountpoint
echo \
'All directory names should be entered relative to the root of the media disc.
'
fi
# now try to get the users idea where the debian
# hierarchy start below the mointpoint
debug "mountpoint: $mountpoint"
while true; do
if ismulti "${mountpoint}" "${hierbase}"; then
multi=yes
fi
echo \
"Need to know where on the media disc the top level of the Debian
distribution is - this will usually contain the 'dists' directory.
If the media disc is badly organized and doesn't have a straightforward copy of
the distribution you may answer 'none' and the needed parts will be prompted
individually."
defhierbase=none
if [ -n "$p_hierbase" ]; then
if [ -d "$mountpoint/$p_hierbase/dists/$dist/main/binary-$iarch" \
-o -n "$multi" ]; 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/dists/$dist/main/binary-$iarch' doesn't seem to exist.
And it does not appear that you are using a multiple media set."
fi
fi
# at this point defhierbase is set if it looks plausible
# if none was entered, we assume a media with a debian/ directory
if [ none = "$defhierbase" -a -d "$mountpoint/debian/dists/$dist/main/binary-$iarch" ]
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 ismulti "$mountpoint" "$response" && [ -z "$multi" ]; then
multi=yes
fi
if ! [ -d "$mountpoint/$response/dists/$dist/main/binary-$iarch" \
-o -n "$multi" ]; then
echo \
"Neither $response/dists/$dist/main/binary-$iarch does not exist,
nor are you using a multiple media set"
break
fi
hierbase="$(echo "$response" | sed -e 's:/$::; s:^/*:/:; s:/\+:/:g;')"
debug "hierbase: [$hierbase]"
if [ -n "$multi" ]; then
disklabel=$(getdisklabel "$mountpoint" "/$response")
echo "Ok, this is disc"
echo " $disklabel"
#echo "Updating multiple media contents file cache ..."
#multi_contentsfile="${mountpoint}/${response}/.disk/contents.gz"
#zcat "$multi_contentsfile" > disk-contents.$option
fi
break;
done
distribution=$dist
if [ -n "$hierbase" ]; then
if [ -d "$mountpoint/$hierbase/dists/unstable/binary-$iarch" ]; 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="$yesno"
if [ "$usedevel" = yes ]; then
distribution=development
fi
else
usedevel=no
fi
echo
fi
case "$hierbase" in
/* )
;;
'' )
;;
* )
hierbase="/$hierbase"
;;
esac
check_binary () {
# args: area-in-messages directory
debug "check_binary($@)"
if [ ! -d "${mountpoint}$2" -a -z "$multi" ]; then
echo "'$2' does not exist."
return
fi
# In this special case it is ok for a sub-distribution to not contain any
# .deb files. Each media should contain all Packages.cd files but does not
# need to contain the .deb files.
#
# if ! { find -L "$mountpoint$2" -name '*.deb' -print \
# | head -1 | grep . ; } >/dev/null 2>&1 && [ -z "$multi" ];
# then
# echo "'$2' does not contain any *.deb packages."
# return
# fi
this_binary="$2"
echo -n "Using '$this_binary' as $1 binary directory"
if [ -n "$multi" ]; then
this_disk=$(getdisklabel ${mountpoint} "/$hierbase")
echo " from disc"
echo " '$this_disk'"
else
echo ""
fi
}
find_area () {
# args: area-in-messages area-in-vars subdirectory-in-hier
# last-time-binary last-time-packages
debug "find_area($@)"
this_binary=''
this_packages=''
this_disk=''
if [ -n "$hierbase" ]; then
check_binary $1 $(echo "$hierbase/dists/$3/$1/binary-$iarch" | sed 's:/\+:/:g')
debug "THIS_BINARY $this_binary"
fi
if [ $2 = nf -a -z "$this_binary" ]; then
echo "
Note: most media distributions of Debian do not include programs available
in the 'non-free' directory of the distribution site.
This is because these programs are under licenses that do not allow source
modification or prevent distribution for profit on a media, or other
restrictions that make them not free software.
If you wish to install these programs you will 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) ?
Say 'none' if this area is not available."
if [ $2 != main -a -z "$defaultbinary" ]; then
defaultbinary=none
fi
echo -n \
"Enter _$1_ binary directory. [$4]
? "
read response
if [ -z "$response" -a -n "$defaultbinary" ]; then
response="$defaultbinary"
fi
if [ none = "$response" ]; then
break
fi
case "$response" in
'' | none)
continue
;;
esac
check_binary $1 "$(echo "$response" | sed -e 's:/$::; s:^/*:/:')"
done
if [ -n "$this_binary" ]; then
if [ "$multi" = "yes" ]; then
for f in Packages.cd.gz packages.cd.gz Packages.cd packages.cd; do
if [ -f "$mountpoint/$this_binary/$f" ]; then
this_packages="$this_binary/$f"
echo "Using '$this_packages' for $1."
break
fi
done
elif [ -f "${mountpoint}${hierbase}/.disk/packages/$1/Packages.gz" ]; then
this_packages=$(echo "${hierbase}/.disk/packages/$1/Packages.gz"|sed 's:/\+:/:g')
echo "Using '${this_packages}' for $1."
fi
while [ -z "$this_packages" ]; do
echo -n "
Cannot find the $1 'Packages.cd' file. The information in the
'Packages.cd' 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.cd file and one Packages.cd.gz file -- either will do --
in the 'binary' subdirectory of each area on the FTP sites and
media discs. Alternatively (and this will be rather slow) the packages in
the distribution area can be scanned - say 'scan' if you want to do so.
You need a separate Packages.cd file from each of the distribution areas
you wish to install.
Where is the _$1_ 'Packages.cd' file (if none is available, say 'none')
[$5]
? "
read response
if [ -z "$response" -a -n "$5" ]; then
response="$5"
fi
case "$response" in
'')
break
;;
none)
break
;;
scan)
this_packages=scan
;;
/*)
this_packages="$response"
;;
*)
this_packages="/$response"
;;
esac
done
fi
eval $2'_binary="$this_binary"'
eval $2'_packages="$this_packages"'
eval $2'_disk="$this_disk"'
}
find_area main main "$distribution" "$p_main_binary" "$p_main_packages"
find_area contrib ctb "$distribution" "$p_ctb_binary" "$p_ctb_packages"
find_area non-free-firmware nff "$distribution" "$p_nff_binary" "$p_nff_packages"
find_area non-free nf "$distribution" "$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_hierbase "$hierbase"
outputparam p_usedevel "$usedevel"
outputparam p_main_packages "$main_packages"
outputparam p_main_binary "$main_binary"
outputparam p_main_disk "$main_disk"
outputparam p_ctb_packages "$ctb_packages"
outputparam p_ctb_binary "$ctb_binary"
outputparam p_ctb_disk "$ctb_disk"
outputparam p_nff_packages "$nff_packages"
outputparam p_nff_binary "$nff_binary"
outputparam p_nff_disk "$nff_disk"
outputparam p_nf_packages "$nf_packages"
outputparam p_nf_binary "$nf_binary"
outputparam p_nf_disk "$nf_disk"
outputparam p_lcl_packages "$lcl_packages"
outputparam p_lcl_binary "$lcl_binary"
outputparam p_multi "$multi"
outputparam p_multi_contentsfile "$multi_contentsfile"
mv shvar.$option.new shvar.$option
xit=0

121
dselect/methods/media/update.sh Executable file
View file

@ -0,0 +1,121 @@
#!/bin/sh
#
# Copyright © 1995-1998 Ian Jackson <ijackson@chiark.greenend.org.uk>
# Copyright © 1998 Heiko Schlittermann <hs@schlittermann.de>
#
# 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 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, see <https://www.gnu.org/licenses/>.
set -e
vardir="$1"
method=$2
option=$3
iarch=$(dpkg --print-architecture)
cd "$vardir/methods/$method"
. ./shvar.$option
#debug() { echo "DEBUG: $@"; }
debug() {
true
}
packages=0
for f in main ctb nf lcl; do
eval 'this_packages=$p_'$f'_packages'
if [ -n "$this_packages" ]; then
packages=1
fi
done
if [ $packages eq 0 ]; then
echo '
No Packages files available, cannot update available packages list.
Hit RETURN to continue. '
read response
exit 0
fi
xit=1
trap '
for area in main ctb nf lcl; do
rm -f packages-$area
done
if [ -n "$umount" ]; then
umount "$umount" >/dev/null 2>&1
fi
exit $xit
' 0
if [ ! -b "$p_blockdev" ]; then
loop=",loop"
fi
if [ -n "$p_blockdev" ]; then
umount="$p_mountpoint"
mount -rt "$p_fstype" -o nosuid,nodev${loop} "$p_blockdev" "$p_mountpoint"
fi
updatetype=update
if [ -z "$p_multi" ]; then
exit 1
fi
for f in main ctb nf lcl; do
eval 'this_packages=$p_'$f'_packages'
case "$this_packages" in
'')
continue
;;
scan)
eval 'this_binary=$p_'$f'_binary'
if [ -z "$this_binary" ]; then
continue
fi
if [ "$updatetype" = update ]; then
dpkg --clear-avail
updatetype=merge
fi
echo Running dpkg --record-avail -R "$p_mountpoint$this_binary"
dpkg --record-avail -R "$p_mountpoint$this_binary"
;;
*)
packagesfile="$p_mountpoint$this_packages"
case "$packagesfile" in
*.gz)
echo -n "Uncompressing $packagesfile ... "
zcat <"$packagesfile" >packages-$f
echo done.
dpkg --$updatetype-avail packages-$f
updatetype=merge
;;
'')
;;
*)
dpkg --$updatetype-avail "$packagesfile"
updatetype=merge
;;
esac
;;
esac
done
cp -f $vardir/available $vardir/methods/$method
echo -n 'Update OK. Hit RETURN. '
read response
xit=0

294
dselect/methparse.cc Normal file
View file

@ -0,0 +1,294 @@
/*
* dselect - Debian package maintenance user interface
* methparse.cc - access method list parsing
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2008-2011, 2013-2015 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <dpkg/i18n.h>
#include <dpkg/c-ctype.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/file.h>
#include "dselect.h"
#include "bindings.h"
#include "method.h"
int noptions=0;
struct dselect_option *options = nullptr, *coption = nullptr;
struct method *methods = nullptr;
static void DPKG_ATTR_NORET
badmethod(varbuf &pathname, const char *why)
{
ohshit(_("syntax error in method options file '%.250s' -- %s"),
pathname.str(), why);
}
static void DPKG_ATTR_NORET
eofmethod(varbuf &pathname, FILE *f, const char *why)
{
if (ferror(f))
ohshite(_("error reading options file '%.250s'"), pathname.str());
badmethod(pathname,why);
}
void readmethods(const char *pathbase, dselect_option **optionspp, int *nread) {
static const char *const methodprograms[]= {
METHODSETUPSCRIPT,
METHODUPDATESCRIPT,
METHODINSTALLSCRIPT,
nullptr
};
const char *const *ccpp;
int methodlen;
DIR *dir;
FILE *names;
struct dirent *dent;
struct varbuf vb;
method *meth;
dselect_option *opt;
varbuf path;
path += pathbase;
path += "/";
dir = opendir(path.str());
if (!dir) {
if (errno == ENOENT)
return;
ohshite(_("unable to read '%.250s' directory for reading methods"),
path.str());
}
debug(dbg_general, "readmethods('%s',...) directory open", pathbase);
while ((dent = readdir(dir)) != nullptr) {
int c = dent->d_name[0];
debug(dbg_general, "readmethods('%s',...) considering '%s' ...",
pathbase, dent->d_name);
if (c != '_' && !c_isalpha(c))
continue;
char *p = dent->d_name + 1;
while ((c = *p) != 0 && c_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);
/* Check if there is a localized version of this method */
path.reset();
path += pathbase;
path += "/";
path += dent->d_name;
path += "/";
varbuf pathmeth;
for (ccpp= methodprograms; *ccpp; ccpp++) {
pathmeth = path;
pathmeth += *ccpp;
if (access(pathmeth.str(), R_OK | X_OK))
ohshite(_("unable to access method script '%.250s'"), pathmeth.str());
}
debug(dbg_general, " readmethods('%s',...) scripts ok", pathbase);
varbuf pathopts;
pathopts = path;
pathopts += METHODOPTIONSFILE;
names = fopen(pathopts.str(), "r");
if (!names)
ohshite(_("unable to read method options file '%.250s'"), pathopts.str());
meth= new method;
meth->name = varbuf(dent->d_name);
meth->path = path;
meth->next= methods;
meth->prev = nullptr;
if (methods)
methods->prev = meth;
methods= meth;
debug(dbg_general, " readmethods('%s',...) new method"
" name='%s' path='%s'",
pathbase, meth->name.str(), meth->path.str());
while ((c= fgetc(names)) != EOF) {
if (c_isspace(c))
continue;
opt= new dselect_option;
opt->meth= meth;
vb.reset();
do {
if (!c_isdigit(c))
badmethod(pathopts, _("non-digit where digit wanted"));
vb += c;
c= fgetc(names);
if (c == EOF)
eofmethod(pathopts, names, _("end of file in index string"));
} while (!c_isspace(c));
if (vb.len() > OPTIONINDEXMAXLEN)
badmethod(pathopts, _("index string too long"));
opt->index = vb;
do {
if (c == '\n')
badmethod(pathopts, _("newline before option name start"));
c= fgetc(names);
if (c == EOF)
eofmethod(pathopts, names, _("end of file before option name start"));
} while (c_isspace(c));
vb.reset();
if (!c_isalpha(c) && c != '_')
badmethod(pathopts, _("nonalpha where option name start wanted"));
do {
if (!c_isalnum(c) && c != '_')
badmethod(pathopts, _("non-alphanum in option name"));
vb += c;
c= fgetc(names);
if (c == EOF)
eofmethod(pathopts, names, _("end of file in option name"));
} while (!c_isspace(c));
opt->name = vb;
do {
if (c == '\n')
badmethod(pathopts, _("newline before summary"));
c= fgetc(names);
if (c == EOF)
eofmethod(pathopts, names, _("end of file before summary"));
} while (c_isspace(c));
vb.reset();
do {
vb += c;
c= fgetc(names);
if (c == EOF)
eofmethod(pathopts, names, _("end of file in summary - missing newline"));
} while (c != '\n');
opt->summary = vb;
varbuf pathoptsdesc;
pathoptsdesc += pathopts;
pathoptsdesc += OPTIONSDESCPFX;
pathoptsdesc += opt->name;
dpkg_error err = DPKG_ERROR_INIT;
if (file_slurp(pathoptsdesc.str(), &opt->description, &err) < 0) {
if (err.syserrno != ENOENT)
dpkg_error_print(&err, _("cannot load option description file '%s'"),
pathoptsdesc.str());
}
debug(dbg_general,
" readmethods('%s',...) new option index='%s' name='%s'"
" summary='%.20s' len(description=%s)=%zu method name='%s'"
" path='%s'",
pathbase,
opt->index.str(), opt->name.str(), opt->summary.str(),
opt->description.len() ? "'...'" : "<none>",
opt->description.len() ? opt->description.len() : -1,
opt->meth->name.str(), opt->meth->path.str());
dselect_option **optinsert = optionspp;
while (*optinsert && strcmp(opt->index.str(), (*optinsert)->index.str()) > 0)
optinsert = &(*optinsert)->next;
opt->next= *optinsert;
*optinsert= opt;
(*nread)++;
}
if (ferror(names))
ohshite(_("error during read of method options file '%.250s'"), pathopts.str());
fclose(names);
}
closedir(dir);
debug(dbg_general, "readmethods('%s',...) done", pathbase);
}
static char *methoptfile = nullptr;
void getcurrentopt() {
char methoptbuf[IMETHODMAXLEN+1+IOPTIONMAXLEN+2];
FILE *cmo;
int l;
char *p;
if (methoptfile == nullptr)
methoptfile = dpkg_db_get_path(CMETHOPTFILE);
coption = nullptr;
cmo= fopen(methoptfile,"r");
if (!cmo) {
if (errno == ENOENT) return;
ohshite(_("unable to open current option file '%.250s'"), methoptfile);
}
debug(dbg_general, "getcurrentopt() cmethopt open");
if (!fgets(methoptbuf,sizeof(methoptbuf),cmo)) { fclose(cmo); return; }
if (fgetc(cmo) != EOF) { fclose(cmo); return; }
if (!feof(cmo)) { fclose(cmo); return; }
debug(dbg_general, "getcurrentopt() cmethopt eof");
fclose(cmo);
debug(dbg_general, "getcurrentopt() cmethopt read");
l= strlen(methoptbuf); if (!l || methoptbuf[l-1] != '\n') return;
methoptbuf[--l]= 0;
debug(dbg_general, "getcurrentopt() cmethopt len and newline");
p= strchr(methoptbuf,' '); if (!p) return;
debug(dbg_general, "getcurrentopt() cmethopt space");
*p++= 0;
debug(dbg_general, "getcurrentopt() cmethopt meth name '%s'", methoptbuf);
method *meth = methods;
while (meth && strcmp(methoptbuf, meth->name.str()))
meth = meth->next;
if (!meth) return;
debug(dbg_general, "getcurrentopt() cmethopt meth found; opt '%s'", p);
dselect_option *opt = options;
while (opt && (opt->meth != meth || strcmp(p, opt->name.str())))
opt = opt->next;
if (!opt) return;
debug(dbg_general, "getcurrentopt() cmethopt opt found");
coption= opt;
}
void writecurrentopt() {
struct atomic_file *file;
if (methoptfile == nullptr)
internerr("method options filename is nullptr");
file = atomic_file_new(methoptfile, ATOMIC_FILE_NORMAL);
atomic_file_open(file);
if (fprintf(file->fp, "%s %s\n", coption->meth->name.str(), coption->name.str()) == EOF)
ohshite(_("unable to write new option to '%.250s'"), file->name_new);
atomic_file_close(file);
atomic_file_commit(file);
atomic_file_free(file);
}

144
dselect/mkcurkeys.pl Executable file
View file

@ -0,0 +1,144 @@
#!/usr/bin/perl
#
# dselect - Debian package maintenance user interface
# mkcurkeys.pl - generate strings mapping key names to ncurses numbers
#
# Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
die 'usage: mkcurkeys.pl <filename> <curses.h>' if @ARGV != 2;
my (%over, %base, %name);
open(my $override_fh, '<', $ARGV[0]) or die $!;
while (<$override_fh>) {
chomp;
/^#/ && next; # skip comments
/\S/ || next; # ignore blank lines
if (/^(\w+)\s+(\S.*\S)\s*$/) {
$over{$1} = $2;
$base{$1} = '';
} else {
die "cannot parse line:\n$_\n";
}
}
close($override_fh);
my $let = 'A';
for my $i (1 .. 26) {
$name{$i} = "^$let";
$base{$i} = '';
$let++;
}
open(my $header_fh, '<', $ARGV[1]) or die $!;
while (<$header_fh>) {
s/\s+$//;
m/#define KEY_(\w+)\s+\d+\s+/p || next;
my $rhs = ${^POSTMATCH};
my $k = "KEY_$1";
$base{$k} = capit($1);
$rhs =~ s/(\w)[\(\)]/$1/g;
$rhs =~ s/\w+ \((\w+)\)/$1/;
next unless $rhs =~ m{^/\* (\w[\w ]+\w) \*/$};
my $name = $1;
$name =~ s/ key$//;
if ($name =~ s/^shifted /shift /) {
next if $name =~ m/ .* .* /;
} else {
next if $name =~ m/ .* /;
}
$name{$k} = capit($name);
}
close($header_fh);
printf(<<'END') or die $!;
/*
* WARNING - THIS FILE IS GENERATED AUTOMATICALLY - DO NOT EDIT
* It is generated by mkcurkeys.pl from <curses.h>
* and keyoverride. If you want to override things try adding
* them to keyoverride.
*/
END
my ($comma);
for my $i (33 .. 126) {
my $k = $i;
my $v = pack('C', $i);
if ($v eq ',') { $comma = $k; next; }
p($k, $v);
}
## no critic (BuiltinFunctions::ProhibitReverseSortBlock)
for my $k (sort {
looks_like_number($a) ?
looks_like_number($b) ? $a <=> $b : -1
: looks_like_number($b) ? 1 :
$a cmp $b
} keys %base) {
## use critic
my $v;
$v = $base{$k};
$v = $name{$k} if defined($name{$k});
$v = $over{$k} if defined($over{$k});
next if $v eq '[elide]';
p($k, $v);
}
for my $i (1 .. 63) {
p("KEY_F($i)", "F$i");
}
p($comma, ',');
print(<<'END') or die $!;
{ -1, nullptr }
END
close(STDOUT) or die $!;
exit(0);
sub capit {
my $str = shift;
my $o = '';
$str =~ y/A-Z/a-z/;
$str = " $str";
while ($str =~ m/ (\w)/p) {
$o .= ${^PREMATCH} . ' ';
$str = $1;
$str =~ y/a-z/A-Z/;
$o .= $str;
$str = ${^POSTMATCH};
}
$str = $o . $str;
$str =~ s/^ //;
return $str;
}
sub p {
my ($k, $v) = @_;
$v =~ s/(["\\])/\\$1/g;
printf(" { %-15s \"%-20s },\n", $k . ',', $v . '"') or die $!;
}

353
dselect/pkgcmds.cc Normal file
View file

@ -0,0 +1,353 @@
/*
* dselect - Debian package maintenance user interface
* pkgcmds.cc - package list keyboard commands
*
* Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <string.h>
#include <stdio.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
#include "pkglist.h"
bool
packagelist::affectedmatches(struct pkginfo *pkg, struct pkginfo *comparewith) {
switch (statsortorder) {
case sso_avail:
if (comparewith->clientdata->ssavail != pkg->clientdata->ssavail)
return false;
break;
case sso_state:
if (comparewith->clientdata->ssstate != pkg->clientdata->ssstate)
return false;
break;
case sso_unsorted:
break;
default:
internerr("unknown statsortorder %d", statsortorder);
}
if (comparewith->priority != PKG_PRIO_UNSET &&
(comparewith->priority != pkg->priority ||
(comparewith->priority == PKG_PRIO_OTHER &&
strcasecmp(comparewith->otherpriority, pkg->otherpriority))))
return false;
if (comparewith->section &&
strcasecmp(comparewith->section,
pkg->section ?
pkg->section : ""))
return false;
return true;
}
void packagelist::affectedrange(int *startp, int *endp) {
if (table[cursorline]->pkg->set->name) {
*startp= cursorline;
*endp= cursorline+1;
return;
}
int index = cursorline;
while (index < nitems && !table[index]->pkg->set->name)
index++;
if (index >= nitems) {
*startp= *endp= cursorline;
return;
}
*startp= index;
while (index < nitems && affectedmatches(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();
}
pkgwant
packagelist::reallywant(pkgwant nwarg, struct perpackagestate *pkgstate)
{
if (nwarg != PKG_WANT_SENTINEL)
return nwarg;
pkgstatus status = pkgstate->pkg->status;
if (status == PKG_STAT_NOTINSTALLED)
return PKG_WANT_PURGE;
if (status == PKG_STAT_CONFIGFILES)
return PKG_WANT_DEINSTALL;
return PKG_WANT_INSTALL;
}
void
packagelist::setwant(pkgwant nwarg)
{
int bot;
if (modstatdb_get_status() == msdbrw_readonly) {
beep();
return;
}
if (recursive) {
redrawitemsrange(cursorline,cursorline+1);
table[cursorline]->selected= reallywant(nwarg,table[cursorline]);
redraw1item(cursorline);
bot= cursorline+1;
} else {
int top;
pkgwant nw;
packagelist *sub = new packagelist(bindings, nullptr);
affectedrange(&top,&bot);
for (int index = top; index < bot; index++) {
if (!table[index]->pkg->set->name)
continue;
nw= reallywant(nwarg,table[index]);
if (table[index]->selected == nw ||
(table[index]->selected == PKG_WANT_PURGE &&
nw == PKG_WANT_DEINSTALL))
continue;
sub->add(table[index]->pkg,nw);
}
repeatedlydisplay(sub,dp_may,this);
for (int index = top; index < bot; index++)
redraw1item(index);
}
movecursorafter(bot);
}
bool manual_install = false;
void packagelist::kd_select() {
manual_install = true;
setwant(PKG_WANT_INSTALL);
manual_install = false;
}
void packagelist::kd_hold() { setwant(PKG_WANT_HOLD); }
void packagelist::kd_deselect() { setwant(PKG_WANT_DEINSTALL); }
void packagelist::kd_unhold() { setwant(PKG_WANT_SENTINEL); }
void packagelist::kd_purge() { setwant(PKG_WANT_PURGE); }
int
would_like_to_install(pkgwant wantvalue, pkginfo *pkg)
{
/* Returns: 1 for yes, 0 for no, -1 for if they want to preserve an error condition. */
debug(dbg_general, "would_like_to_install(%d, %s) status %d",
wantvalue, pkg_name(pkg, pnaw_always), pkg->status);
if (wantvalue == PKG_WANT_INSTALL)
return 1;
if (wantvalue != PKG_WANT_HOLD)
return 0;
if (pkg->status == PKG_STAT_INSTALLED)
return 1;
if (pkg->status == PKG_STAT_NOTINSTALLED ||
pkg->status == PKG_STAT_CONFIGFILES)
return 0;
return -1;
}
const char *packagelist::itemname(int index) {
return table[index]->pkg->set->name;
}
void packagelist::kd_swapstatorder() {
if (sortorder == so_unsorted) return;
switch (statsortorder) {
case sso_avail: statsortorder= sso_state; break;
case sso_state: statsortorder= sso_unsorted; break;
case sso_unsorted: statsortorder= sso_avail; break;
default:
internerr("unknown statsort %d", statsortorder);
}
resortredisplay();
}
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 %d", sortorder);
}
resortredisplay();
}
void packagelist::resortredisplay() {
const char *oldname = table[cursorline]->pkg->set->name;
sortmakeheads();
int newcursor;
newcursor= 0;
if (oldname) {
int index;
for (index=0; index<nitems; index++) {
if (table[index]->pkg->set->name &&
strcasecmp(oldname, table[index]->pkg->set->name) == 0) {
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_archdisplay()
{
switch (archdisplayopt) {
case ado_both:
archdisplayopt = ado_none;
break;
case ado_none:
archdisplayopt = ado_available;
break;
case ado_available:
archdisplayopt = ado_both;
break;
default:
internerr("unknown archdisplayopt %d", archdisplayopt);
}
setwidths();
leftofscreen = 0;
ldrawnstart = ldrawnend = -1;
redrawtitle();
redrawcolheads();
redrawitemsrange(topofscreen, min(topofscreen + list_height, nitems));
refreshlist();
}
void packagelist::kd_versiondisplay() {
switch (versiondisplayopt) {
case vdo_both: versiondisplayopt= vdo_none; break;
case vdo_none: versiondisplayopt= vdo_available; break;
case vdo_available: versiondisplayopt= vdo_both; break;
default:
internerr("unknown versiondisplayopt %d", versiondisplayopt);
}
setwidths();
leftofscreen= 0;
ldrawnstart= ldrawnend= -1;
redrawtitle();
redrawcolheads();
redrawitemsrange(topofscreen, min(topofscreen + list_height, nitems));
refreshlist();
}
void packagelist::kd_verbose() {
verbose= !verbose;
setwidths();
leftofscreen= 0;
ldrawnstart= ldrawnend= -1;
redrawtitle();
redrawcolheads();
redrawitemsrange(topofscreen, min(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->set->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->set->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->set->name)
table[index]->selected= table[index]->suggested;
ldrawnstart= ldrawnend= -1;
}
refreshlist(); redrawthisstate();
}
void
packagelist::kd_revertinstalled()
{
int i;
for (i = 0; i < nitems; i++) {
if (table[i]->pkg->set->name)
table[i]->selected = reallywant(PKG_WANT_SENTINEL, table[i]);
ldrawnstart = ldrawnend = -1;
}
refreshlist();
redrawthisstate();
}
/* FIXME: configurable purge/deselect */
void packagelist::kd_toggleinfo() {
showinfo= (showinfo+2) % 3;
setheights();
if (cursorline >= topofscreen+list_height) topofscreen += list_height;
if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
if (topofscreen < 0) topofscreen= 0;
infotopofscreen= 0;
redraw1item(cursorline);
refreshlist();
redrawthisstate();
redrawinfo();
}
void packagelist::kd_info() {
if (!showinfo) {
showinfo= 2; kd_toggleinfo();
} else {
currentinfo++;
infotopofscreen=0;
redrawinfo();
}
}

461
dselect/pkgdepcon.cc Normal file
View file

@ -0,0 +1,461 @@
/*
* dselect - Debian package maintenance user interface
* pkgdepcon.cc - dependency and conflict resolution
*
* Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
* Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
*
* 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 of the License, 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 program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <compat.h>
#include <string.h>
#include <stdio.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include "dselect.h"
#include "pkglist.h"
bool
packagelist::useavailable(pkginfo *pkg)
{
if (pkg->clientdata &&
pkg->clientdata->selected == PKG_WANT_INSTALL &&
pkg_is_informative(pkg, &pkg->available) &&
(!(pkg->status == PKG_STAT_INSTALLED ||
pkg->status == PKG_STAT_TRIGGERSAWAITED ||
pkg->status == PKG_STAT_TRIGGERSPENDING) ||
dpkg_version_compare(&pkg->available.version,
&pkg->installed.version) > 0))
return true;
else
return false;
}
pkgbin *
packagelist::find_pkgbin(pkginfo *pkg)
{
pkgbin *pkgbin;
pkgbin = useavailable(pkg) ? &pkg->available : &pkg->installed;
debug(dbg_general, "packagelist[%p]::find_pkgbin(%s) useavailable=%d",
this, pkgbin_name(pkg, pkgbin, pnaw_always), useavailable(pkg));
return pkgbin;
}
int packagelist::checkdependers(pkginfo *pkg, int changemade) {
struct deppossi *possi;
for (possi = pkg->set->depended.available; possi; possi = possi->rev_next) {
if (!useavailable(possi->up->up))
continue;
changemade = max(changemade, resolvedepcon(possi->up));
}
for (possi = pkg->set->depended.installed; possi; possi = possi->rev_next) {
if (useavailable(possi->up->up))
continue;
changemade = max(changemade, resolvedepcon(possi->up));
}
return changemade;
}
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 Conflicts,
// or 1 if we offered or made a change because of an Optional line.
debug(dbg_general, "packagelist[%p]::resolvesuggest()", this);
int maxchangemade = 0;
for (;;) {
int changemade = 0;
int index;
for (index=0; index<nitems; index++) {
if (!table[index]->pkg->set->name)
continue;
debug(dbg_depcon, "packagelist[%p]::resolvesuggest() loop[%i] %s / %d",
this, index, pkg_name(table[index]->pkg, pnaw_always), changemade);
dependency *depends;
for (depends = find_pkgbin(table[index]->pkg)->depends;
depends;
depends= depends->next) {
changemade = max(changemade, resolvedepcon(depends));
}
changemade= checkdependers(table[index]->pkg,changemade);
for (depends = find_pkgbin(table[index]->pkg)->depends;
depends;
depends= depends->next) {
if (depends->type != dep_provides) continue;
changemade = checkdependers(&depends->list->ed->pkg, changemade);
}
debug(dbg_depcon, "packagelist[%p]::resolvesuggest() loop[%i] %s / -> %d",
this, index, pkg_name(table[index]->pkg, pnaw_always), changemade);
}
if (!changemade) break;
maxchangemade = max(maxchangemade, changemade);
}
debug(dbg_general, "packagelist[%p]::resolvesuggest() done; maxchangemade=%d",
this, maxchangemade);
return maxchangemade;
}
static bool
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 false;
debug(dbg_depcon, "update_best_to_change(best=%s{%d}, test=%s{%d});",
best ? pkg_name(best->pkg, pnaw_always) : "",
best ? best->spriority : -1,
trythis->set->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 true;
// If we haven't found anything yet then this is our best so far.
if (!best) goto yes;
// If only one of the packages is available, use that one
if (!pkg_is_informative(trythis, &trythis->available) &&
pkg_is_informative(best->pkg, &best->pkg->available))
return false;
if (pkg_is_informative(trythis, &trythis->available) &&
!pkg_is_informative(best->pkg, &best->pkg->available))
goto yes;
// Select the package with the lowest priority (i.e., the one of whom
// we were least sure we wanted it deselected).
if (trythis->clientdata->spriority > best->spriority)
return false;
if (trythis->clientdata->spriority < best->spriority) goto yes;
// Pick the package with the must fundamental recommendation level.
if (trythis->priority > best->pkg->priority)
return false;
if (trythis->priority < best->pkg->priority) goto yes;
// If we're still unsure we'll change the first one in the list.
return false;
yes:
debug(dbg_depcon, "update_best_to_change(); yes");
best = trythis->clientdata;
return false;
}
int
packagelist::deselect_one_of(pkginfo *per, pkginfo *ped, dependency *dep)
{
perpackagestate *er= per->clientdata;
perpackagestate *ed= ped->clientdata;
if (!er || !would_like_to_install(er->selected,per) ||
!ed || !would_like_to_install(ed->selected,ped)) return 0;
add(dep, dp_must);
er= per->clientdata; // these can be changed by add
ed= ped->clientdata;
debug(dbg_depcon,
"packagelist[%p]::deselect_one_of(): er %s{%d} ed %s{%d} [%p]",
this, pkg_name(er->pkg, pnaw_always), er->spriority,
pkg_name(ed->pkg, pnaw_always), ed->spriority, dep);
perpackagestate *best;
// Try not keep packages needing reinstallation.
if (per->eflag & PKG_EFLAG_REINSTREQ)
best = ed;
else if (ped->eflag & PKG_EFLAG_REINSTREQ)
best = er;
// We'd rather change the one with the lowest priority.
else if (er->spriority > ed->spriority)
best = ed;
else if (er->spriority < ed->spriority)
best = er;
// ... failing that the one with the highest priority.
else if (er->pkg->priority < ed->pkg->priority)
best = ed;
else if (er->pkg->priority > ed->pkg->priority)
best = er;
// ... failing that, the second.
else
best = ed;
debug(dbg_depcon, "packagelist[%p]::deselect_one_of(): best %s{%d}",
this, pkg_name(best->pkg, pnaw_always), best->spriority);
if (best->spriority >= sp_deselecting) return 0;
best->suggested=
best->pkg->status == PKG_STAT_NOTINSTALLED
? PKG_WANT_PURGE : PKG_WANT_DEINSTALL; // FIXME: configurable.
best->selected= best->suggested;
best->spriority= sp_deselecting;
return 2;
}
int packagelist::resolvedepcon(dependency *depends) {
perpackagestate *best, *fixbyupgrade;
deppossi *possi, *provider;
bool foundany;
int rc;
if (debug_has_flag(dbg_depcon)) {
varbuf pkg_names;
for (possi = depends->list; possi; possi = possi->next) {
pkg_names += ' ';
pkg_names += possi->ed->name;
}
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p] %s --%s-->%s); (ing)->want=%s",
this, depends, pkg_name(depends->up, pnaw_always),
relatestrings[depends->type],
pkg_names.str(), depends->up->clientdata ?
wantstrings[depends->up->clientdata->suggested] : "(no clientdata)");
}
if (!depends->up->clientdata) return 0;
switch (depends->type) {
case dep_provides:
case dep_replaces:
return 0;
case dep_enhances:
case dep_suggests:
case dep_recommends:
case dep_depends:
case dep_predepends:
if (would_like_to_install(depends->up->clientdata->selected,depends->up) <= 0)
return 0;
fixbyupgrade = nullptr;
possi = depends->list;
while (possi && !deppossatisfied(possi, &fixbyupgrade))
possi = possi->next;
debug(dbg_depcon, "packagelist[%p]::resolvedepcon([%p]): depends found %s",
this, depends, possi ? possi->ed->name : "[none]");
if (possi) return 0;
// Ensures all in the recursive list; adds info strings; ups priorities
switch (depends->type) {
case dep_enhances:
case dep_suggests:
rc = add(depends, dp_may);
return rc;
case dep_recommends:
rc = add(depends, dp_should);
break;
default:
rc = add(depends, dp_must);
}
if (fixbyupgrade) {
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): fixbyupgrade %s",
this, depends, pkg_name(fixbyupgrade->pkg, pnaw_always));
best= fixbyupgrade;
} else {
best = nullptr;
for (possi= depends->list;
possi;
possi= possi->next) {
foundany = false;
if (possi->ed->pkg.clientdata)
foundany = true;
if (dep_update_best_to_change_stop(best, &possi->ed->pkg))
goto mustdeselect;
for (provider = possi->ed->depended.available;
provider;
provider = provider->rev_next) {
if (provider->up->type != dep_provides) continue;
if (provider->up->up->clientdata)
foundany = true;
if (dep_update_best_to_change_stop(best, provider->up->up)) goto mustdeselect;
}
if (!foundany) addunavailable(possi);
}
if (!best) {
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): mustdeselect nobest",
this, depends);
return rc;
}
}
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): select best=%s{%d}",
this, depends, pkg_name(best->pkg, pnaw_always), best->spriority);
if (best->spriority >= sp_selecting)
return rc;
/* Always select depends. Only select recommends if we got here because
* of a manually-initiated install request. */
if (depends->type != dep_recommends || manual_install) {
best->selected = best->suggested = PKG_WANT_INSTALL;
best->spriority= sp_selecting;
}
return rc ? 2 : 0;
mustdeselect:
best= depends->up->clientdata;
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): mustdeselect best=%s{%d}",
this, depends, pkg_name(best->pkg, pnaw_always), best->spriority);
if (best->spriority >= sp_deselecting)
return rc;
/* Always remove depends, but never remove recommends. */
if (depends->type != dep_recommends) {
best->selected= best->suggested=
best->pkg->status == PKG_STAT_NOTINSTALLED
? PKG_WANT_PURGE : PKG_WANT_DEINSTALL; // FIXME: configurable
best->spriority= sp_deselecting;
}
return rc ? 2 : 0;
case dep_conflicts:
case dep_breaks:
debug(dbg_depcon, "packagelist[%p]::resolvedepcon([%p]): conflict",
this, depends);
if (would_like_to_install(depends->up->clientdata->selected,depends->up) == 0)
return 0;
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): conflict installing 1",
this, depends);
if (!deppossatisfied(depends->list, nullptr))
return 0;
debug(dbg_depcon,
"packagelist[%p]::resolvedepcon([%p]): conflict satisfied - ouch",
this, depends);
if (depends->up->set != depends->list->ed) {
rc = deselect_one_of(depends->up, &depends->list->ed->pkg, depends);
if (rc)
return rc;
}
for (provider = depends->list->ed->depended.available;
provider;
provider = provider->rev_next) {
if (provider->up->type != dep_provides) continue;
if (provider->up->up == depends->up) continue; // conflicts & provides same thing
rc = deselect_one_of(depends->up, provider->up->up, depends);
if (rc)
return rc;
}
debug(dbg_depcon, "packagelist[%p]::resolvedepcon([%p]): no desel",
this, depends);
return 0;
default:
internerr("unknown deptype %d", depends->type);
}
/* never reached, make gcc happy */
return 1;
}
bool
packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade)
{
// satisfied here for Conflicts and Breaks means that the
// restriction is violated, that is, that the target package is wanted
int would;
pkgwant want = PKG_WANT_PURGE;
if (possi->ed->pkg.clientdata) {
want = possi->ed->pkg.clientdata->selected;
would = would_like_to_install(want, &possi->ed->pkg);
} else {
would= 0;
}
if ((possi->up->type == dep_conflicts || possi->up->type == dep_breaks)
? possi->up->up->set != possi->ed && would != 0
: would > 0) {
// If it's to be installed or left 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 (useavailable(&possi->ed->pkg)) {
if (want != PKG_WANT_INSTALL)
internerr("depossi package is not want-install, is %d", want);
return versionsatisfied(&possi->ed->pkg.available, possi);
} else {
if (versionsatisfied(&possi->ed->pkg.installed, possi))
return true;
if (want == PKG_WANT_HOLD && fixbyupgrade && !*fixbyupgrade &&
versionsatisfied(&possi->ed->pkg.available, possi) &&
dpkg_version_compare(&possi->ed->pkg.available.version,
&possi->ed->pkg.installed.version) > 1)
*fixbyupgrade = possi->ed->pkg.clientdata;
return false;
}
}
deppossi *provider;
for (provider = possi->ed->depended.installed;
provider;
provider = provider->rev_next) {
if (provider->up->type == dep_provides &&
((possi->up->type != dep_conflicts && possi->up->type != dep_breaks) ||
provider->up->up->set != possi->up->up->set) &&
provider->up->up->clientdata &&
!useavailable(provider->up->up) &&
would_like_to_install(provider->up->up->clientdata->selected,
provider->up->up) &&
pkg_virtual_deppossi_satisfied(possi, provider))
return true;
}
for (provider = possi->ed->depended.available;
provider;
provider = provider->rev_next) {
if (provider->up->type != dep_provides ||
((possi->up->type == dep_conflicts || possi->up->type == dep_breaks) &&
provider->up->up->set == possi->up->up->set) ||
!provider->up->up->clientdata ||
!would_like_to_install(provider->up->up->clientdata->selected,
provider->up->up) ||
!pkg_virtual_deppossi_satisfied(possi, provider))
continue;
if (useavailable(provider->up->up))
return true;
if (fixbyupgrade && !*fixbyupgrade &&
(!(provider->up->up->status == PKG_STAT_INSTALLED ||
provider->up->up->status == PKG_STAT_TRIGGERSPENDING ||
provider->up->up->status == PKG_STAT_TRIGGERSAWAITED) ||
dpkg_version_compare(&provider->up->up->available.version,
&provider->up->up->installed.version) > 1))
*fixbyupgrade = provider->up->up->clientdata;
}
return false;
}

Some files were not shown because too many files have changed in this diff Show more