summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:58:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:58:51 +0000
commitcbffab246997fb5a06211dfb706b54e5ae5bb59f (patch)
tree0573c5d96f58d74d76a49c0f2a70398e389a36d3 /src
parentInitial commit. (diff)
downloaddpkg-upstream.tar.xz
dpkg-upstream.zip
Adding upstream version 1.21.22.upstream/1.21.22upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am178
-rw-r--r--src/Makefile.in1402
-rw-r--r--src/at/atlocal.in32
-rw-r--r--src/at/chdir.at491
-rw-r--r--src/at/deb-content.at129
-rw-r--r--src/at/deb-fields.at47
-rw-r--r--src/at/deb-format.at601
-rw-r--r--src/at/deb-split.at228
-rw-r--r--src/at/divert.at639
-rw-r--r--src/at/local.at132
-rw-r--r--src/at/package.m47
-rw-r--r--src/at/realpath.at86
-rwxr-xr-xsrc/at/testsuite12702
-rw-r--r--src/at/testsuite.at24
-rw-r--r--src/common/actions.h78
-rw-r--r--src/common/force.c404
-rw-r--r--src/common/force.h85
-rw-r--r--src/common/security-mac.h30
-rw-r--r--src/common/selinux.c156
-rw-r--r--src/deb/build.c730
-rw-r--r--src/deb/dpkg-deb.h87
-rw-r--r--src/deb/extract.c507
-rw-r--r--src/deb/info.c305
-rw-r--r--src/deb/main.c311
-rw-r--r--src/divert/main.c884
-rwxr-xr-xsrc/dpkg-db-backup.sh86
-rwxr-xr-xsrc/dpkg-maintscript-helper.sh667
-rwxr-xr-xsrc/dpkg-realpath.sh179
-rw-r--r--src/main/archives.c1703
-rw-r--r--src/main/archives.h99
-rw-r--r--src/main/cleanup.c260
-rw-r--r--src/main/configure.c829
-rw-r--r--src/main/depcon.c704
-rw-r--r--src/main/enquiry.c906
-rw-r--r--src/main/errors.c137
-rw-r--r--src/main/file-match.c49
-rw-r--r--src/main/file-match.h35
-rw-r--r--src/main/filters.c133
-rw-r--r--src/main/filters.h37
-rw-r--r--src/main/help.c359
-rw-r--r--src/main/main.c779
-rw-r--r--src/main/main.h305
-rw-r--r--src/main/packages.c758
-rw-r--r--src/main/perpkgstate.c43
-rw-r--r--src/main/remove.c688
-rw-r--r--src/main/script.c399
-rw-r--r--src/main/select.c242
-rw-r--r--src/main/trigproc.c576
-rw-r--r--src/main/unpack.c1733
-rw-r--r--src/main/update.c124
-rw-r--r--src/main/verify.c243
-rw-r--r--src/query/main.c881
-rw-r--r--src/sh/dpkg-error.sh93
-rw-r--r--src/split/dpkg-split.h84
-rw-r--r--src/split/info.c291
-rw-r--r--src/split/join.c151
-rw-r--r--src/split/main.c185
-rw-r--r--src/split/queue.c365
-rw-r--r--src/split/split.c287
-rw-r--r--src/statoverride/main.c421
-rw-r--r--src/trigger/main.c270
61 files changed, 35376 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..4358165
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,178 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+ -DLOCALEDIR=\"$(localedir)\" \
+ -DADMINDIR=\"$(admindir)\" \
+ -idirafter $(top_srcdir)/lib/compat \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/lib \
+ -I$(srcdir)/common \
+ # EOL
+LDADD = \
+ ../lib/dpkg/libdpkg.la \
+ $(LIBINTL) \
+ ../lib/compat/libcompat.la \
+ # EOL
+
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+
+nobase_dist_pkgdata_DATA = \
+ sh/dpkg-error.sh \
+ # EOL
+
+bin_PROGRAMS = \
+ dpkg \
+ dpkg-deb \
+ dpkg-divert \
+ dpkg-query \
+ dpkg-split \
+ dpkg-statoverride \
+ dpkg-trigger \
+ # EOL
+
+bin_SCRIPTS = \
+ dpkg-maintscript-helper \
+ dpkg-realpath \
+ # EOL
+
+pkglibexec_SCRIPTS = \
+ dpkg-db-backup \
+ # EOL
+
+EXTRA_DIST += \
+ dpkg-db-backup.sh \
+ dpkg-maintscript-helper.sh \
+ dpkg-realpath.sh \
+ # EOL
+
+CLEANFILES += \
+ $(bin_SCRIPTS) \
+ $(pkglibexec_SCRIPTS) \
+ # EOL
+
+dpkg_SOURCES = \
+ common/actions.h \
+ common/force.c \
+ common/force.h \
+ common/security-mac.h \
+ common/selinux.c \
+ main/archives.c \
+ main/archives.h \
+ main/cleanup.c \
+ main/configure.c \
+ main/depcon.c \
+ main/enquiry.c \
+ main/errors.c \
+ main/file-match.c \
+ main/file-match.h \
+ main/filters.c \
+ main/filters.h \
+ main/help.c \
+ main/main.c \
+ main/main.h \
+ main/packages.c \
+ main/perpkgstate.c \
+ main/remove.c \
+ main/script.c \
+ main/select.c \
+ main/trigproc.c \
+ main/unpack.c \
+ main/update.c \
+ main/verify.c \
+ # EOL
+
+dpkg_LDADD = \
+ $(LDADD) \
+ $(SELINUX_LIBS) \
+ # EOL
+
+dpkg_deb_SOURCES = \
+ deb/dpkg-deb.h \
+ deb/build.c \
+ deb/extract.c \
+ deb/info.c \
+ deb/main.c \
+ # EOL
+
+dpkg_deb_LDADD = \
+ $(LDADD) \
+ $(Z_LIBS) \
+ $(LZMA_LIBS) \
+ $(ZSTD_LIBS) \
+ $(BZ2_LIBS) \
+ # EOL
+
+dpkg_divert_SOURCES = \
+ divert/main.c \
+ # EOL
+
+dpkg_query_SOURCES = \
+ common/actions.h \
+ query/main.c \
+ # EOL
+
+dpkg_split_SOURCES = \
+ split/dpkg-split.h \
+ split/info.c \
+ split/join.c \
+ split/main.c \
+ split/queue.c \
+ split/split.c \
+ # EOL
+
+dpkg_statoverride_SOURCES = \
+ common/actions.h \
+ common/force.c \
+ common/force.h \
+ common/security-mac.h \
+ common/selinux.c \
+ statoverride/main.c \
+ # EOL
+
+dpkg_statoverride_LDADD = \
+ $(LDADD) \
+ $(SELINUX_LIBS) \
+ # EOL
+
+dpkg_trigger_SOURCES = \
+ trigger/main.c \
+ # EOL
+
+SUFFIXES =
+
+include $(top_srcdir)/build-aux/subst.am
+
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(pkgconfdir)/dpkg.cfg.d
+ $(MKDIR_P) $(DESTDIR)$(admindir)/info
+ $(MKDIR_P) $(DESTDIR)$(admindir)/parts
+ $(MKDIR_P) $(DESTDIR)$(admindir)/updates
+
+EXTRA_DIST += $(srcdir)/at/atlocal.in
+EXTRA_DIST += $(srcdir)/at/package.m4
+
+TESTSUITE_AT = $(srcdir)/at/testsuite.at
+TESTSUITE_AT += $(srcdir)/at/local.at
+TESTSUITE_AT += $(srcdir)/at/deb-format.at
+TESTSUITE_AT += $(srcdir)/at/deb-fields.at
+TESTSUITE_AT += $(srcdir)/at/deb-content.at
+TESTSUITE_AT += $(srcdir)/at/deb-split.at
+TESTSUITE_AT += $(srcdir)/at/realpath.at
+TESTSUITE_AT += $(srcdir)/at/divert.at
+TESTSUITE_AT += $(srcdir)/at/chdir.at
+EXTRA_DIST += $(TESTSUITE_AT)
+
+TESTSUITE = $(srcdir)/at/testsuite
+EXTRA_DIST += $(TESTSUITE)
+
+DISTCLEANFILES += at/atconfig
+
+include $(top_srcdir)/build-aux/autotest.am
+
+check-local: autotest-check
+
+installcheck-local: autotest-installcheck
+
+clean-local: autotest-clean
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..0cb0672
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1402 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 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))
+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@
+bin_PROGRAMS = dpkg$(EXEEXT) dpkg-deb$(EXEEXT) dpkg-divert$(EXEEXT) \
+ dpkg-query$(EXEEXT) dpkg-split$(EXEEXT) \
+ dpkg-statoverride$(EXEEXT) dpkg-trigger$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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-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_pkgdata_DATA) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkgdatadir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_dpkg_OBJECTS = common/force.$(OBJEXT) common/selinux.$(OBJEXT) \
+ main/archives.$(OBJEXT) main/cleanup.$(OBJEXT) \
+ main/configure.$(OBJEXT) main/depcon.$(OBJEXT) \
+ main/enquiry.$(OBJEXT) main/errors.$(OBJEXT) \
+ main/file-match.$(OBJEXT) main/filters.$(OBJEXT) \
+ main/help.$(OBJEXT) main/main.$(OBJEXT) \
+ main/packages.$(OBJEXT) main/perpkgstate.$(OBJEXT) \
+ main/remove.$(OBJEXT) main/script.$(OBJEXT) \
+ main/select.$(OBJEXT) main/trigproc.$(OBJEXT) \
+ main/unpack.$(OBJEXT) main/update.$(OBJEXT) \
+ main/verify.$(OBJEXT)
+dpkg_OBJECTS = $(am_dpkg_OBJECTS)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = ../lib/dpkg/libdpkg.la $(am__DEPENDENCIES_1) \
+ ../lib/compat/libcompat.la
+dpkg_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_dpkg_deb_OBJECTS = deb/build.$(OBJEXT) deb/extract.$(OBJEXT) \
+ deb/info.$(OBJEXT) deb/main.$(OBJEXT)
+dpkg_deb_OBJECTS = $(am_dpkg_deb_OBJECTS)
+dpkg_deb_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_dpkg_divert_OBJECTS = divert/main.$(OBJEXT)
+dpkg_divert_OBJECTS = $(am_dpkg_divert_OBJECTS)
+dpkg_divert_LDADD = $(LDADD)
+dpkg_divert_DEPENDENCIES = ../lib/dpkg/libdpkg.la \
+ $(am__DEPENDENCIES_1) ../lib/compat/libcompat.la
+am_dpkg_query_OBJECTS = query/main.$(OBJEXT)
+dpkg_query_OBJECTS = $(am_dpkg_query_OBJECTS)
+dpkg_query_LDADD = $(LDADD)
+dpkg_query_DEPENDENCIES = ../lib/dpkg/libdpkg.la $(am__DEPENDENCIES_1) \
+ ../lib/compat/libcompat.la
+am_dpkg_split_OBJECTS = split/info.$(OBJEXT) split/join.$(OBJEXT) \
+ split/main.$(OBJEXT) split/queue.$(OBJEXT) \
+ split/split.$(OBJEXT)
+dpkg_split_OBJECTS = $(am_dpkg_split_OBJECTS)
+dpkg_split_LDADD = $(LDADD)
+dpkg_split_DEPENDENCIES = ../lib/dpkg/libdpkg.la $(am__DEPENDENCIES_1) \
+ ../lib/compat/libcompat.la
+am_dpkg_statoverride_OBJECTS = common/force.$(OBJEXT) \
+ common/selinux.$(OBJEXT) statoverride/main.$(OBJEXT)
+dpkg_statoverride_OBJECTS = $(am_dpkg_statoverride_OBJECTS)
+dpkg_statoverride_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_dpkg_trigger_OBJECTS = trigger/main.$(OBJEXT)
+dpkg_trigger_OBJECTS = $(am_dpkg_trigger_OBJECTS)
+dpkg_trigger_LDADD = $(LDADD)
+dpkg_trigger_DEPENDENCIES = ../lib/dpkg/libdpkg.la \
+ $(am__DEPENDENCIES_1) ../lib/compat/libcompat.la
+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 -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+SCRIPTS = $(bin_SCRIPTS) $(pkglibexec_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 =
+DEFAULT_INCLUDES =
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = common/$(DEPDIR)/force.Po \
+ common/$(DEPDIR)/selinux.Po deb/$(DEPDIR)/build.Po \
+ deb/$(DEPDIR)/extract.Po deb/$(DEPDIR)/info.Po \
+ deb/$(DEPDIR)/main.Po divert/$(DEPDIR)/main.Po \
+ main/$(DEPDIR)/archives.Po main/$(DEPDIR)/cleanup.Po \
+ main/$(DEPDIR)/configure.Po main/$(DEPDIR)/depcon.Po \
+ main/$(DEPDIR)/enquiry.Po main/$(DEPDIR)/errors.Po \
+ main/$(DEPDIR)/file-match.Po main/$(DEPDIR)/filters.Po \
+ main/$(DEPDIR)/help.Po main/$(DEPDIR)/main.Po \
+ main/$(DEPDIR)/packages.Po main/$(DEPDIR)/perpkgstate.Po \
+ main/$(DEPDIR)/remove.Po main/$(DEPDIR)/script.Po \
+ main/$(DEPDIR)/select.Po main/$(DEPDIR)/trigproc.Po \
+ main/$(DEPDIR)/unpack.Po main/$(DEPDIR)/update.Po \
+ main/$(DEPDIR)/verify.Po query/$(DEPDIR)/main.Po \
+ split/$(DEPDIR)/info.Po split/$(DEPDIR)/join.Po \
+ split/$(DEPDIR)/main.Po split/$(DEPDIR)/queue.Po \
+ split/$(DEPDIR)/split.Po statoverride/$(DEPDIR)/main.Po \
+ trigger/$(DEPDIR)/main.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(dpkg_SOURCES) $(dpkg_deb_SOURCES) $(dpkg_divert_SOURCES) \
+ $(dpkg_query_SOURCES) $(dpkg_split_SOURCES) \
+ $(dpkg_statoverride_SOURCES) $(dpkg_trigger_SOURCES)
+DIST_SOURCES = $(dpkg_SOURCES) $(dpkg_deb_SOURCES) \
+ $(dpkg_divert_SOURCES) $(dpkg_query_SOURCES) \
+ $(dpkg_split_SOURCES) $(dpkg_statoverride_SOURCES) \
+ $(dpkg_trigger_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_pkgdata_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/autotest.am \
+ $(top_srcdir)/build-aux/depcomp \
+ $(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@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+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_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@
+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@
+admindir = @admindir@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+backupsdir = @backupsdir@
+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@
+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@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfdir = @pkgconfdir@
+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@
+AM_CPPFLAGS = \
+ -DLOCALEDIR=\"$(localedir)\" \
+ -DADMINDIR=\"$(admindir)\" \
+ -idirafter $(top_srcdir)/lib/compat \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/lib \
+ -I$(srcdir)/common \
+ # EOL
+
+LDADD = \
+ ../lib/dpkg/libdpkg.la \
+ $(LIBINTL) \
+ ../lib/compat/libcompat.la \
+ # EOL
+
+EXTRA_DIST = dpkg-db-backup.sh dpkg-maintscript-helper.sh \
+ dpkg-realpath.sh $(srcdir)/at/atlocal.in \
+ $(srcdir)/at/package.m4 $(TESTSUITE_AT) $(TESTSUITE) \
+ $(srcdir)/at/package.m4
+CLEANFILES = $(bin_SCRIPTS) $(pkglibexec_SCRIPTS) # EOL
+DISTCLEANFILES = at/atconfig at/atconfig
+nobase_dist_pkgdata_DATA = \
+ sh/dpkg-error.sh \
+ # EOL
+
+bin_SCRIPTS = \
+ dpkg-maintscript-helper \
+ dpkg-realpath \
+ # EOL
+
+pkglibexec_SCRIPTS = \
+ dpkg-db-backup \
+ # EOL
+
+dpkg_SOURCES = \
+ common/actions.h \
+ common/force.c \
+ common/force.h \
+ common/security-mac.h \
+ common/selinux.c \
+ main/archives.c \
+ main/archives.h \
+ main/cleanup.c \
+ main/configure.c \
+ main/depcon.c \
+ main/enquiry.c \
+ main/errors.c \
+ main/file-match.c \
+ main/file-match.h \
+ main/filters.c \
+ main/filters.h \
+ main/help.c \
+ main/main.c \
+ main/main.h \
+ main/packages.c \
+ main/perpkgstate.c \
+ main/remove.c \
+ main/script.c \
+ main/select.c \
+ main/trigproc.c \
+ main/unpack.c \
+ main/update.c \
+ main/verify.c \
+ # EOL
+
+dpkg_LDADD = \
+ $(LDADD) \
+ $(SELINUX_LIBS) \
+ # EOL
+
+dpkg_deb_SOURCES = \
+ deb/dpkg-deb.h \
+ deb/build.c \
+ deb/extract.c \
+ deb/info.c \
+ deb/main.c \
+ # EOL
+
+dpkg_deb_LDADD = \
+ $(LDADD) \
+ $(Z_LIBS) \
+ $(LZMA_LIBS) \
+ $(ZSTD_LIBS) \
+ $(BZ2_LIBS) \
+ # EOL
+
+dpkg_divert_SOURCES = \
+ divert/main.c \
+ # EOL
+
+dpkg_query_SOURCES = \
+ common/actions.h \
+ query/main.c \
+ # EOL
+
+dpkg_split_SOURCES = \
+ split/dpkg-split.h \
+ split/info.c \
+ split/join.c \
+ split/main.c \
+ split/queue.c \
+ split/split.c \
+ # EOL
+
+dpkg_statoverride_SOURCES = \
+ common/actions.h \
+ common/force.c \
+ common/force.h \
+ common/security-mac.h \
+ common/selinux.c \
+ statoverride/main.c \
+ # EOL
+
+dpkg_statoverride_LDADD = \
+ $(LDADD) \
+ $(SELINUX_LIBS) \
+ # EOL
+
+dpkg_trigger_SOURCES = \
+ trigger/main.c \
+ # EOL
+
+SUFFIXES = .sh .pl
+do_shell_subst = $(AM_V_GEN) $(SED) \
+ -e "s:^ADMINDIR=.*$$:ADMINDIR='$(admindir)':" \
+ -e "s:^BACKUPSDIR=.*$$:BACKUPSDIR='$(backupsdir)':" \
+ -e "s:^PKGDATADIR_DEFAULT=.*$$:PKGDATADIR_DEFAULT='$(pkgdatadir)':" \
+ -e "s:^version=['\"][^'\"]*[\"']:version=\"$(PACKAGE_VERSION)\":" \
+ # EOL
+
+
+# Perl support.
+do_perl_subst = $(AM_V_GEN) $(SED) \
+ -e "s:^\#![[:space:]]*/usr/bin/perl:\#!$(PERL):" \
+ -e "s:our \$$CONFDIR = .*;:our \$$CONFDIR = '$(pkgconfdir)';:" \
+ -e "s:our \$$ADMINDIR = .*;:our \$$ADMINDIR = '$(admindir)';:" \
+ -e "s:our \$$LIBDIR = .*;:our \$$LIBDIR = '$(pkglibexecdir)';:" \
+ -e "s:our \$$DATADIR = .*;:our \$$DATADIR = '$(pkgdatadir)';:" \
+ -e "s:our \$$PROGMAKE = .*;:our \$$PROGMAKE = '$(MAKE)';:" \
+ -e "s:our \$$PROGTAR = .*;:our \$$PROGTAR = '$(TAR)';:" \
+ -e "s:our \$$PROGPATCH = .*;:our \$$PROGPATCH = '$(PATCH)';:" \
+ -e "s:our \$$PROGVERSION = .*;:our \$$PROGVERSION = '$(PACKAGE_VERSION)';:" \
+ # EOL
+
+
+# Makefile support.
+do_make_subst = $(AM_V_GEN) $(SED) \
+ -e "s:dpkg_datadir[[:space:]]*=[[:space:]]*[^[:space:]]*:dpkg_datadir = $(pkgdatadir):" \
+ # EOL
+
+TESTSUITE_AT = $(srcdir)/at/testsuite.at $(srcdir)/at/local.at \
+ $(srcdir)/at/deb-format.at $(srcdir)/at/deb-fields.at \
+ $(srcdir)/at/deb-content.at $(srcdir)/at/deb-split.at \
+ $(srcdir)/at/realpath.at $(srcdir)/at/divert.at \
+ $(srcdir)/at/chdir.at
+TESTSUITE = $(srcdir)/at/testsuite
+AUTOTEST_DEPS = at/atconfig at/atlocal $(TESTSUITE)
+AUTOTEST = $(AUTOM4TE) --language=autotest
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .sh .pl .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/build-aux/subst.am $(top_srcdir)/build-aux/autotest.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 src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/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 $(top_srcdir)/build-aux/autotest.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-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ 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; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+common/$(am__dirstamp):
+ @$(MKDIR_P) common
+ @: > common/$(am__dirstamp)
+common/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) common/$(DEPDIR)
+ @: > common/$(DEPDIR)/$(am__dirstamp)
+common/force.$(OBJEXT): common/$(am__dirstamp) \
+ common/$(DEPDIR)/$(am__dirstamp)
+common/selinux.$(OBJEXT): common/$(am__dirstamp) \
+ common/$(DEPDIR)/$(am__dirstamp)
+main/$(am__dirstamp):
+ @$(MKDIR_P) main
+ @: > main/$(am__dirstamp)
+main/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) main/$(DEPDIR)
+ @: > main/$(DEPDIR)/$(am__dirstamp)
+main/archives.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/cleanup.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/configure.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/depcon.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/enquiry.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/errors.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/file-match.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/filters.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/help.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/main.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/packages.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/perpkgstate.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/remove.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/script.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/select.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/trigproc.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/unpack.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/update.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+main/verify.$(OBJEXT): main/$(am__dirstamp) \
+ main/$(DEPDIR)/$(am__dirstamp)
+
+dpkg$(EXEEXT): $(dpkg_OBJECTS) $(dpkg_DEPENDENCIES) $(EXTRA_dpkg_DEPENDENCIES)
+ @rm -f dpkg$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_OBJECTS) $(dpkg_LDADD) $(LIBS)
+deb/$(am__dirstamp):
+ @$(MKDIR_P) deb
+ @: > deb/$(am__dirstamp)
+deb/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) deb/$(DEPDIR)
+ @: > deb/$(DEPDIR)/$(am__dirstamp)
+deb/build.$(OBJEXT): deb/$(am__dirstamp) deb/$(DEPDIR)/$(am__dirstamp)
+deb/extract.$(OBJEXT): deb/$(am__dirstamp) \
+ deb/$(DEPDIR)/$(am__dirstamp)
+deb/info.$(OBJEXT): deb/$(am__dirstamp) deb/$(DEPDIR)/$(am__dirstamp)
+deb/main.$(OBJEXT): deb/$(am__dirstamp) deb/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-deb$(EXEEXT): $(dpkg_deb_OBJECTS) $(dpkg_deb_DEPENDENCIES) $(EXTRA_dpkg_deb_DEPENDENCIES)
+ @rm -f dpkg-deb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_deb_OBJECTS) $(dpkg_deb_LDADD) $(LIBS)
+divert/$(am__dirstamp):
+ @$(MKDIR_P) divert
+ @: > divert/$(am__dirstamp)
+divert/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) divert/$(DEPDIR)
+ @: > divert/$(DEPDIR)/$(am__dirstamp)
+divert/main.$(OBJEXT): divert/$(am__dirstamp) \
+ divert/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-divert$(EXEEXT): $(dpkg_divert_OBJECTS) $(dpkg_divert_DEPENDENCIES) $(EXTRA_dpkg_divert_DEPENDENCIES)
+ @rm -f dpkg-divert$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_divert_OBJECTS) $(dpkg_divert_LDADD) $(LIBS)
+query/$(am__dirstamp):
+ @$(MKDIR_P) query
+ @: > query/$(am__dirstamp)
+query/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) query/$(DEPDIR)
+ @: > query/$(DEPDIR)/$(am__dirstamp)
+query/main.$(OBJEXT): query/$(am__dirstamp) \
+ query/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-query$(EXEEXT): $(dpkg_query_OBJECTS) $(dpkg_query_DEPENDENCIES) $(EXTRA_dpkg_query_DEPENDENCIES)
+ @rm -f dpkg-query$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_query_OBJECTS) $(dpkg_query_LDADD) $(LIBS)
+split/$(am__dirstamp):
+ @$(MKDIR_P) split
+ @: > split/$(am__dirstamp)
+split/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) split/$(DEPDIR)
+ @: > split/$(DEPDIR)/$(am__dirstamp)
+split/info.$(OBJEXT): split/$(am__dirstamp) \
+ split/$(DEPDIR)/$(am__dirstamp)
+split/join.$(OBJEXT): split/$(am__dirstamp) \
+ split/$(DEPDIR)/$(am__dirstamp)
+split/main.$(OBJEXT): split/$(am__dirstamp) \
+ split/$(DEPDIR)/$(am__dirstamp)
+split/queue.$(OBJEXT): split/$(am__dirstamp) \
+ split/$(DEPDIR)/$(am__dirstamp)
+split/split.$(OBJEXT): split/$(am__dirstamp) \
+ split/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-split$(EXEEXT): $(dpkg_split_OBJECTS) $(dpkg_split_DEPENDENCIES) $(EXTRA_dpkg_split_DEPENDENCIES)
+ @rm -f dpkg-split$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_split_OBJECTS) $(dpkg_split_LDADD) $(LIBS)
+statoverride/$(am__dirstamp):
+ @$(MKDIR_P) statoverride
+ @: > statoverride/$(am__dirstamp)
+statoverride/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) statoverride/$(DEPDIR)
+ @: > statoverride/$(DEPDIR)/$(am__dirstamp)
+statoverride/main.$(OBJEXT): statoverride/$(am__dirstamp) \
+ statoverride/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-statoverride$(EXEEXT): $(dpkg_statoverride_OBJECTS) $(dpkg_statoverride_DEPENDENCIES) $(EXTRA_dpkg_statoverride_DEPENDENCIES)
+ @rm -f dpkg-statoverride$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_statoverride_OBJECTS) $(dpkg_statoverride_LDADD) $(LIBS)
+trigger/$(am__dirstamp):
+ @$(MKDIR_P) trigger
+ @: > trigger/$(am__dirstamp)
+trigger/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) trigger/$(DEPDIR)
+ @: > trigger/$(DEPDIR)/$(am__dirstamp)
+trigger/main.$(OBJEXT): trigger/$(am__dirstamp) \
+ trigger/$(DEPDIR)/$(am__dirstamp)
+
+dpkg-trigger$(EXEEXT): $(dpkg_trigger_OBJECTS) $(dpkg_trigger_DEPENDENCIES) $(EXTRA_dpkg_trigger_DEPENDENCIES)
+ @rm -f dpkg-trigger$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dpkg_trigger_OBJECTS) $(dpkg_trigger_LDADD) $(LIBS)
+install-binSCRIPTS: $(bin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ 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 'h;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 \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
+install-pkglibexecSCRIPTS: $(pkglibexec_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglibexec_SCRIPTS)'; test -n "$(pkglibexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
+ fi; \
+ 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 'h;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 \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-pkglibexecSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglibexec_SCRIPTS)'; test -n "$(pkglibexecdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pkglibexecdir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f common/*.$(OBJEXT)
+ -rm -f deb/*.$(OBJEXT)
+ -rm -f divert/*.$(OBJEXT)
+ -rm -f main/*.$(OBJEXT)
+ -rm -f query/*.$(OBJEXT)
+ -rm -f split/*.$(OBJEXT)
+ -rm -f statoverride/*.$(OBJEXT)
+ -rm -f trigger/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/force.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/selinux.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@deb/$(DEPDIR)/build.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@deb/$(DEPDIR)/extract.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@deb/$(DEPDIR)/info.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@deb/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@divert/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/archives.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/cleanup.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/configure.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/depcon.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/enquiry.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/errors.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/file-match.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/filters.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/help.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/packages.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/perpkgstate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/remove.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/script.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/select.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/trigproc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/unpack.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/update.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/verify.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@query/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@split/$(DEPDIR)/info.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@split/$(DEPDIR)/join.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@split/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@split/$(DEPDIR)/queue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@split/$(DEPDIR)/split.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@statoverride/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@trigger/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-nobase_dist_pkgdataDATA: $(nobase_dist_pkgdata_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(nobase_dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || 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)$(pkgdatadir)/$$dir'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)/$$dir"; }; \
+ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(pkgdatadir)/$$dir'"; \
+ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(pkgdatadir)/$$dir" || exit $$?; }; \
+ done
+
+uninstall-nobase_dist_pkgdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nobase_dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+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
+ $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkgdatadir)"; 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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f common/$(DEPDIR)/$(am__dirstamp)
+ -rm -f common/$(am__dirstamp)
+ -rm -f deb/$(DEPDIR)/$(am__dirstamp)
+ -rm -f deb/$(am__dirstamp)
+ -rm -f divert/$(DEPDIR)/$(am__dirstamp)
+ -rm -f divert/$(am__dirstamp)
+ -rm -f main/$(DEPDIR)/$(am__dirstamp)
+ -rm -f main/$(am__dirstamp)
+ -rm -f query/$(DEPDIR)/$(am__dirstamp)
+ -rm -f query/$(am__dirstamp)
+ -rm -f split/$(DEPDIR)/$(am__dirstamp)
+ -rm -f split/$(am__dirstamp)
+ -rm -f statoverride/$(DEPDIR)/$(am__dirstamp)
+ -rm -f statoverride/$(am__dirstamp)
+ -rm -f trigger/$(DEPDIR)/$(am__dirstamp)
+ -rm -f trigger/$(am__dirstamp)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+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-binPROGRAMS clean-generic clean-libtool clean-local \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f common/$(DEPDIR)/force.Po
+ -rm -f common/$(DEPDIR)/selinux.Po
+ -rm -f deb/$(DEPDIR)/build.Po
+ -rm -f deb/$(DEPDIR)/extract.Po
+ -rm -f deb/$(DEPDIR)/info.Po
+ -rm -f deb/$(DEPDIR)/main.Po
+ -rm -f divert/$(DEPDIR)/main.Po
+ -rm -f main/$(DEPDIR)/archives.Po
+ -rm -f main/$(DEPDIR)/cleanup.Po
+ -rm -f main/$(DEPDIR)/configure.Po
+ -rm -f main/$(DEPDIR)/depcon.Po
+ -rm -f main/$(DEPDIR)/enquiry.Po
+ -rm -f main/$(DEPDIR)/errors.Po
+ -rm -f main/$(DEPDIR)/file-match.Po
+ -rm -f main/$(DEPDIR)/filters.Po
+ -rm -f main/$(DEPDIR)/help.Po
+ -rm -f main/$(DEPDIR)/main.Po
+ -rm -f main/$(DEPDIR)/packages.Po
+ -rm -f main/$(DEPDIR)/perpkgstate.Po
+ -rm -f main/$(DEPDIR)/remove.Po
+ -rm -f main/$(DEPDIR)/script.Po
+ -rm -f main/$(DEPDIR)/select.Po
+ -rm -f main/$(DEPDIR)/trigproc.Po
+ -rm -f main/$(DEPDIR)/unpack.Po
+ -rm -f main/$(DEPDIR)/update.Po
+ -rm -f main/$(DEPDIR)/verify.Po
+ -rm -f query/$(DEPDIR)/main.Po
+ -rm -f split/$(DEPDIR)/info.Po
+ -rm -f split/$(DEPDIR)/join.Po
+ -rm -f split/$(DEPDIR)/main.Po
+ -rm -f split/$(DEPDIR)/queue.Po
+ -rm -f split/$(DEPDIR)/split.Po
+ -rm -f statoverride/$(DEPDIR)/main.Po
+ -rm -f trigger/$(DEPDIR)/main.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-nobase_dist_pkgdataDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-binSCRIPTS \
+ install-pkglibexecSCRIPTS
+
+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: installcheck-local
+
+maintainer-clean: maintainer-clean-am
+ -rm -f common/$(DEPDIR)/force.Po
+ -rm -f common/$(DEPDIR)/selinux.Po
+ -rm -f deb/$(DEPDIR)/build.Po
+ -rm -f deb/$(DEPDIR)/extract.Po
+ -rm -f deb/$(DEPDIR)/info.Po
+ -rm -f deb/$(DEPDIR)/main.Po
+ -rm -f divert/$(DEPDIR)/main.Po
+ -rm -f main/$(DEPDIR)/archives.Po
+ -rm -f main/$(DEPDIR)/cleanup.Po
+ -rm -f main/$(DEPDIR)/configure.Po
+ -rm -f main/$(DEPDIR)/depcon.Po
+ -rm -f main/$(DEPDIR)/enquiry.Po
+ -rm -f main/$(DEPDIR)/errors.Po
+ -rm -f main/$(DEPDIR)/file-match.Po
+ -rm -f main/$(DEPDIR)/filters.Po
+ -rm -f main/$(DEPDIR)/help.Po
+ -rm -f main/$(DEPDIR)/main.Po
+ -rm -f main/$(DEPDIR)/packages.Po
+ -rm -f main/$(DEPDIR)/perpkgstate.Po
+ -rm -f main/$(DEPDIR)/remove.Po
+ -rm -f main/$(DEPDIR)/script.Po
+ -rm -f main/$(DEPDIR)/select.Po
+ -rm -f main/$(DEPDIR)/trigproc.Po
+ -rm -f main/$(DEPDIR)/unpack.Po
+ -rm -f main/$(DEPDIR)/update.Po
+ -rm -f main/$(DEPDIR)/verify.Po
+ -rm -f query/$(DEPDIR)/main.Po
+ -rm -f split/$(DEPDIR)/info.Po
+ -rm -f split/$(DEPDIR)/join.Po
+ -rm -f split/$(DEPDIR)/main.Po
+ -rm -f split/$(DEPDIR)/queue.Po
+ -rm -f split/$(DEPDIR)/split.Po
+ -rm -f statoverride/$(DEPDIR)/main.Po
+ -rm -f trigger/$(DEPDIR)/main.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-nobase_dist_pkgdataDATA uninstall-pkglibexecSCRIPTS
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
+ check-local clean clean-binPROGRAMS clean-generic \
+ clean-libtool clean-local cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-binSCRIPTS 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_pkgdataDATA \
+ install-pdf install-pdf-am install-pkglibexecSCRIPTS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installcheck-local installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-nobase_dist_pkgdataDATA uninstall-pkglibexecSCRIPTS
+
+.PRECIOUS: Makefile
+
+
+.sh: Makefile
+ @test -d `dirname $@` || $(MKDIR_P) `dirname $@`
+ $(do_shell_subst) <$< >$@
+ $(AM_V_at) chmod +x $@
+
+.pl: Makefile
+ @test -d `dirname $@` || $(MKDIR_P) `dirname $@`
+ $(do_perl_subst) <$< >$@
+ $(AM_V_at) chmod +x $@
+
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(pkgconfdir)/dpkg.cfg.d
+ $(MKDIR_P) $(DESTDIR)$(admindir)/info
+ $(MKDIR_P) $(DESTDIR)$(admindir)/parts
+ $(MKDIR_P) $(DESTDIR)$(admindir)/updates
+
+# 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
+$(TESTSUITE): $(srcdir)/at/package.m4 $(TESTSUITE_AT)
+ $(AUTOTEST) -I '$(srcdir)/at' -o $@.tmp $@.at
+ mv $@.tmp $@
+
+check-local: autotest-check
+
+installcheck-local: autotest-installcheck
+
+clean-local: autotest-clean
+
+# 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:
diff --git a/src/at/atlocal.in b/src/at/atlocal.in
new file mode 100644
index 0000000..bf72333
--- /dev/null
+++ b/src/at/atlocal.in
@@ -0,0 +1,32 @@
+# Global shell definitions for the autotest test suite
+
+PATH="@abs_top_builddir@/src:$PATH"
+export PATH
+
+SED=@SED@
+PERL=@PERL@
+
+# Setup a sane environment
+
+umask 0022
+
+LC_ALL=C
+export LC_ALL
+
+TZ=UTC0
+export TZ
+
+SOURCE_DATE_EPOCH=0
+export SOURCE_DATE_EPOCH
+
+prefix="@prefix@"
+eval "export DEFAULT_ADMINDIR='@admindir@'"
+export DPKG_DATADIR="@abs_top_srcdir@/src"
+
+# Cleanup variables that might affect the tests.
+unset GZIP
+unset BZIP
+unset XZ_OPT
+unset XZ_DEFAULTS
+
+unset DPKG_ROOT
diff --git a/src/at/chdir.at b/src/at/chdir.at
new file mode 100644
index 0000000..ec9299f
--- /dev/null
+++ b/src/at/chdir.at
@@ -0,0 +1,491 @@
+#
+# Test commands with --root, --instdir and --admindir.
+#
+
+m4_foreach_w([CMD], [dpkg dpkg-divert dpkg-statoverride], [
+ m4_define([CMD_PRINT_DIRS], [DPKG_DEBUG=1 CMD --version])
+
+ AT_SETUP([CMD chdir opts])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --root=/rootdir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [CMD_PRINT_DIRS --instdir=/instdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_env
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt admindir])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_env
+])
+ AT_CHECK(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt root])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/rootdir_env$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt root+admindir])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_env
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --instdir=/instdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt],
+ [], [ignore],
+ [D000001: root=/instdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+])
+
+#
+# Test commands with only --root and --admindir.
+#
+
+m4_foreach_w([CMD], [dpkg-split dpkg-query dpkg-trigger], [
+ m4_define([CMD_PRINT_DIRS], [DPKG_DEBUG=1 CMD --version])
+
+ AT_SETUP([CMD chdir opts])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+])
+
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+
+ AT_CHECK_UNQUOTED(
+ [CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+])
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+])
+
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_env
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt admindir])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt root])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+
+ AT_SETUP([CMD chdir env+opt root+admindir])
+ AT_KEYWORDS([CMD command-line chdir])
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_env admindir=/admindir_opt
+])
+ AT_CHECK(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --root=/rootdir_opt --admindir=/admindir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/admindir_opt
+])
+ AT_CHECK_UNQUOTED(
+ [DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ CMD_PRINT_DIRS --admindir=/admindir_opt --root=/rootdir_opt],
+ [], [ignore],
+ [D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+])
+
+ AT_CLEANUP
+])
diff --git a/src/at/deb-content.at b/src/at/deb-content.at
new file mode 100644
index 0000000..f475603
--- /dev/null
+++ b/src/at/deb-content.at
@@ -0,0 +1,129 @@
+AT_SETUP([dpkg-deb .deb conffiles])
+AT_KEYWORDS([dpkg-deb deb conffiles])
+
+DPKG_GEN_CONTROL([pkg-conff-duped])
+DPKG_GEN_CTRL_FILE([pkg-conff-duped], [conffiles], [/test-conffile-1
+/test-conffile-2
+/test-conffile-1])
+AT_DATA([pkg-conff-duped/test-conffile-1], [test init
+])
+AT_DATA([pkg-conff-duped/test-conffile-2], [test init
+])
+AT_CHECK([
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-duped
+], [0], [ignore], [dpkg-deb: warning: conffile name '/test-conffile-1' is duplicated
+dpkg-deb: warning: ignoring 1 warning about the control file(s)
+])
+
+DPKG_GEN_CONTROL([pkg-conff-noeol])
+printf "/test-conffile-1" >"pkg-conff-noeol/DEBIAN/conffiles"
+AT_DATA([pkg-conff-noeol/test-conffile-1], [test init
+])
+AT_CHECK([
+# Conffiles need a final newline to guarantee there's been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-noeol pkg-conff-noeol.deb
+], [2], [ignore], [dpkg-deb: error: conffile name '/test-conffile-1' is too long, or missing final newline
+])
+
+DPKG_GEN_CONTROL([pkg-conff-noabs])
+DPKG_GEN_CTRL_FILE([pkg-conff-noabs], [conffiles], [test-conffile-rel])
+AT_DATA([pkg-conff-noabs/test-conffile-rel], [test init
+])
+AT_CHECK([
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-noabs pkg-conff-noabs.deb
+], [2], [ignore], [dpkg-deb: error: conffile name 'test-conffile-rel' is not an absolute pathname
+])
+
+DPKG_GEN_CONTROL([pkg-conff-empty])
+printf " \n" >"pkg-conff-empty/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles must not contain empty lines.
+dpkg-deb -b pkg-conff-empty pkg-conff-empty.deb
+], [2], [ignore], [dpkg-deb: error: empty and whitespace-only lines are not allowed in conffiles
+])
+
+DPKG_GEN_CONTROL([pkg-conff-space-prefix])
+DPKG_GEN_CTRL_FILE([pkg-conff-space-prefix], [conffiles], [ /test-conffile])
+AT_CHECK([
+# Conffiles must not contain prefixed spaces.
+dpkg-deb -b pkg-conff-space-prefix pkg-conff-space-prefix.deb
+], [2], [ignore], [dpkg-deb: error: line with conffile filename '/test-conffile' has leading white spaces
+])
+
+DPKG_GEN_CONTROL([pkg-conff-unknown-flag])
+DPKG_GEN_CTRL_FILE([pkg-conff-unknown-flag], [conffiles], [unknown-flag /test-conffile])
+AT_CHECK([
+# Conffiles marked with an unknown flag.
+dpkg-deb -b pkg-conff-unknown-flag pkg-conff-unknown-flag.deb
+], [2], [ignore], [dpkg-deb: error: unknown flag 'unknown-flag' for conffile '/test-conffile'
+])
+
+DPKG_GEN_CONTROL([pkg-conff-missing-pathname])
+printf "unknown-flag \n" >"pkg-conff-missing-pathname/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles need a pathname, in addition to a flag.
+dpkg-deb -b pkg-conff-missing-pathname pkg-conff-missing-pathname.deb
+], [2], [ignore], [dpkg-deb: error: conffile name missing after flag 'unknown-flag'
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-missing])
+DPKG_GEN_CTRL_FILE([pkg-conff-removed-missing], [conffiles], [remove-on-upgrade /test-conffile-missing])
+AT_CHECK([
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-missing pkg-conff-removed-missing.deb
+], [0], [ignore], [])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-duped])
+DPKG_GEN_CTRL_FILE([pkg-conff-removed-duped], [conffiles], [remove-on-upgrade /test-conffile-1
+remove-on-upgrade /test-conffile-2
+remove-on-upgrade /test-conffile-1])
+AT_CHECK([
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-removed-duped
+], [0], [ignore], [dpkg-deb: warning: conffile name '/test-conffile-1' is duplicated
+dpkg-deb: warning: ignoring 1 warning about the control file(s)
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-noeol])
+printf "remove-on-upgrade /test-conffile-1" >"pkg-conff-removed-noeol/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles need a final newline to guarantee there has been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-removed-noeol pkg-conff-removed-noeol.deb
+], [2], [ignore], [dpkg-deb: error: conffile name 'remove-on-upgrade /test-conffile-1' is too long, or missing final newline
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-noabs])
+DPKG_GEN_CTRL_FILE([pkg-conff-removed-noabs], [conffiles], [remove-on-upgrade test-conffile-rel])
+AT_DATA([pkg-conff-removed-noabs/test-conffile-rel], [test init
+])
+AT_CHECK([
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-removed-noabs pkg-conff-removed-noabs.deb
+], [2], [ignore], [dpkg-deb: error: conffile name 'test-conffile-rel' is not an absolute pathname
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-present])
+DPKG_GEN_CTRL_FILE([pkg-conff-removed-present], [conffiles], [remove-on-upgrade /test-conffile-present])
+AT_DATA([pkg-conff-removed-present/test-conffile-present], [test init
+])
+AT_CHECK([
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-present pkg-conff-removed-present.deb
+], [2], [ignore], [dpkg-deb: error: conffile '/test-conffile-present' is present but is requested to be removed
+])
+
+DPKG_GEN_CONTROL([pkg-deb-newline])
+touch 'pkg-deb-newline/file
+newline'
+AT_CHECK([
+# Cannot create package with newlines in filenames.
+dpkg-deb -b pkg-deb-newline
+], [2], [ignore], [dpkg-deb: error: newline not allowed in pathname './file
+newline'
+])
+
+AT_CLEANUP
diff --git a/src/at/deb-fields.at b/src/at/deb-fields.at
new file mode 100644
index 0000000..484ccb7
--- /dev/null
+++ b/src/at/deb-fields.at
@@ -0,0 +1,47 @@
+AT_SETUP([dpkg-deb .deb fields])
+AT_KEYWORDS([dpkg-deb deb fields])
+
+DPKG_GEN_CONTROL([pkg-package-type-void])
+AT_CHECK([
+dpkg-deb -b pkg-package-type-void
+# Test absence of Package-Type field.
+test -z "$(dpkg-deb -f pkg-package-type-void.deb Package-Type)"
+], [0], [ignore])
+
+DPKG_GEN_CONTROL([pkg-package-type-use])
+DPKG_MOD_CONTROL([pkg-package-type-use], [/^Package:/aPackage-Type: udeb])
+AT_CHECK([
+dpkg-deb -b pkg-package-type-use
+# Test presence of Package-Type field.
+test -n "$(dpkg-deb -f pkg-package-type-use.deb Package-Type)"
+], [0], [ignore])
+
+DPKG_GEN_CONTROL([pkg-obsolete-fields])
+DPKG_MOD_CONTROL([pkg-obsolete-fields], [s/^Priority:/Class:/])
+DPKG_MOD_CONTROL([pkg-obsolete-fields], [s/^Version: 0.0-1/Version: 0.0/])
+DPKG_MOD_CONTROL([pkg-obsolete-fields], [/^Version:/aRevision: 1])
+DPKG_MOD_CONTROL([pkg-obsolete-fields], [/^Package:/aOptional: suggests])
+DPKG_MOD_CONTROL([pkg-obsolete-fields], [/^Package:/aRecommended: recommends])
+AT_CHECK([
+dpkg-deb -b pkg-obsolete-fields
+], [0], [ignore],
+[dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 2 package 'pkg-obsolete-fields':
+ obsolete 'Recommended' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 3 package 'pkg-obsolete-fields':
+ obsolete 'Optional' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 5 package 'pkg-obsolete-fields':
+ obsolete 'Revision' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 7 package 'pkg-obsolete-fields':
+ obsolete 'Class' field used
+dpkg-deb: warning: ignoring 4 warnings about the control file(s)
+])
+AT_CHECK([
+dpkg-deb -f pkg-obsolete-fields.deb \
+ Version Recommends Suggests Priority 2>/dev/null
+], [0], [Version: 0.0-1
+Recommends: recommends
+Suggests: suggests
+Priority: extra
+])
+
+AT_CLEANUP
diff --git a/src/at/deb-format.at b/src/at/deb-format.at
new file mode 100644
index 0000000..c3b412f
--- /dev/null
+++ b/src/at/deb-format.at
@@ -0,0 +1,601 @@
+AT_SETUP([dpkg-deb options])
+AT_KEYWORDS([dpkg-deb command-line])
+
+AT_CHECK([dpkg-deb --version], [], [ignore])
+AT_CHECK([dpkg-deb --help], [], [ignore])
+
+AT_CLEANUP
+
+
+AT_SETUP([dpkg-deb .deb format 0.93x])
+AT_KEYWORDS([dpkg-deb deb-old])
+
+AT_SKIP_IF([! command -v gzip >/dev/null])
+
+AT_DATA([pkg-deb-old-bogus-only-version.deb], [0.93
+])
+AT_CHECK([
+# Check truncated old deb w/ only version magic
+dpkg-deb --info pkg-deb-old-bogus-only-version.deb
+], [2], [], [dpkg-deb: error: unexpected end of file in archive control member size in pkg-deb-old-bogus-only-version.deb
+])
+
+DPKG_GEN_CONTROL([pkg-deb-old-format])
+DPKG_MOD_CONTROL([pkg-deb-old-format],
+ [s/^Description:.*$/& - deb old format support/])
+AT_DATA([pkg-deb-old-format/file-templ], [test
+])
+AT_CHECK([
+# Initialize the template package
+mv pkg-deb-old-format pkg-old-templ
+cp $top_srcdir/ChangeLog.old pkg-old-templ/
+chmod 0644 pkg-old-templ/ChangeLog.old
+chmod -R u+w pkg-old-templ
+find pkg-old-templ | xargs touch -t 197001010100.00
+dpkg-deb --deb-format=0.939000 --root-owner-group -Zgzip -b pkg-old-templ >/dev/null
+
+dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar
+gzip -n fsys.tar
+
+# Create deb-old 0.939
+cp pkg-old-templ.deb pkg-old.deb
+
+# Create deb-old-old-old 0.931
+mkdir -p pkg-old-0931-templ/.DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0931-templ/.DEBIAN/
+find pkg-old-0931-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0931.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0931-templ .DEBIAN
+
+echo '0.931000' >pkg-old-0931.deb
+DPKG_FILE_SIZE([ctrl-0931.tar.gz]) >>pkg-old-0931.deb
+cat ctrl-0931.tar.gz >>pkg-old-0931.deb
+cat fsys.tar.gz >>pkg-old-0931.deb
+
+# Create deb-old-old template
+mkdir -p pkg-old-0932-templ/DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0932-templ/DEBIAN/
+find pkg-old-0932-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0932.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0932-templ DEBIAN
+
+# Create deb-old-old 0.932
+echo '0.932000' >pkg-old-0932.deb
+DPKG_FILE_SIZE([ctrl-0932.tar.gz]) >>pkg-old-0932.deb
+cat ctrl-0932.tar.gz >>pkg-old-0932.deb
+cat fsys.tar.gz >>pkg-old-0932.deb
+
+# Create deb-old-old 0.933
+echo '0.933000' >pkg-old-0933.deb
+DPKG_FILE_SIZE([ctrl-0932.tar.gz]) >>pkg-old-0933.deb
+cat ctrl-0932.tar.gz >>pkg-old-0933.deb
+cat fsys.tar.gz >>pkg-old-0933.deb
+])
+
+AT_CHECK([
+# Check old package metadata
+dpkg-deb -I pkg-old.deb | $SED -e 's/ *$//'
+], [], [ old Debian package, version 0.939000.
+ size 174621 bytes: control archive=274, main archive=174334.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+])
+
+AT_CHECK([
+# Check old package metadata
+dpkg-deb -I pkg-old-0931.deb | $SED -e 's/ *$//'
+], [], [ old Debian package, version 0.931000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+])
+
+AT_CHECK([
+# Check old package metadata
+dpkg-deb -I pkg-old-0932.deb | $SED -e 's/ *$//'
+], [], [ old Debian package, version 0.932000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+])
+
+AT_CHECK([
+# Check old package metadata
+dpkg-deb -I pkg-old-0933.deb | $SED -e 's/ *$//'
+], [], [ old Debian package, version 0.933000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+])
+
+AT_CHECK([
+# Check old package contents
+dpkg-deb -c pkg-old.deb
+], [], [drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Check old package contents
+dpkg-deb -c pkg-old-0931.deb
+], [], [drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Check old package contents
+dpkg-deb -c pkg-old-0932.deb
+], [], [drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Check old package contents
+dpkg-deb -c pkg-old-0933.deb
+], [], [drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CLEANUP
+
+
+AT_SETUP([dpkg-deb .deb format 2.x])
+AT_KEYWORDS([dpkg-deb deb])
+
+AT_SKIP_IF([! command -v xz >/dev/null])
+AT_SKIP_IF([! command -v gzip >/dev/null])
+AT_SKIP_IF([! command -v zstd >/dev/null])
+AT_SKIP_IF([! command -v bzip2 >/dev/null])
+AT_SKIP_IF([! command -v lzma >/dev/null])
+
+AT_DATA([pkg-deb-bogus-empty.deb], [])
+AT_CHECK([
+# Check truncated deb w/ 0 size
+dpkg-deb --info pkg-deb-bogus-empty.deb
+], [2], [], [dpkg-deb: error: unexpected end of file in archive magic version number in pkg-deb-bogus-empty.deb
+])
+
+DPKG_GEN_CONTROL([pkg-deb-format])
+DPKG_MOD_CONTROL([pkg-deb-format],
+ [s/^Description:.*$/& - deb format support/])
+AT_DATA([pkg-deb-format/file-templ], [test
+])
+AT_CHECK([
+# Initialize the template package
+mv pkg-deb-format pkg-templ
+cp $top_srcdir/ChangeLog.old pkg-templ/
+chmod 0644 pkg-templ/ChangeLog.old
+chmod -R u+w pkg-templ
+find pkg-templ | xargs touch -t 197001010100.00
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ >/dev/null
+
+# Extract the base members
+ar x pkg-templ.deb
+gzip -c control.tar >control.tar.gz
+gzip -c data.tar >data.tar.gz
+xz -c control.tar >control.tar.xz
+xz -c data.tar >data.tar.xz
+zstd -c control.tar >control.tar.zst
+zstd -c data.tar >data.tar.zst
+bzip2 -c data.tar >data.tar.bz2
+lzma -c data.tar >data.tar.lzma
+touch _ignore
+touch unknown
+])
+
+AT_CHECK([
+# Test debian-binary with 2.x versions
+cp pkg-templ.deb pkg-version-2x.deb
+echo 2.999 >debian-binary
+ar rc pkg-version-2x.deb debian-binary
+ar t pkg-version-2x.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-version-2x.deb | $SED -e 's/ *$//'
+], [], [debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.999.
+ size 655554 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+])
+
+AT_CHECK([
+# Test debian-binary with extra lines
+cp pkg-templ.deb pkg-magic-extra.deb
+echo "extra line" >>debian-binary
+ar rc pkg-magic-extra.deb debian-binary
+ar t pkg-magic-extra.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-magic-extra.deb | $SED -e 's/ *$//'
+], [], [debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655564 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+])
+
+AT_CHECK([
+# Test missing debian-binary member
+cp pkg-templ.deb pkg-missing-magic.deb
+ar d pkg-missing-magic.deb debian-binary
+ar t pkg-missing-magic.deb
+dpkg-deb -I pkg-missing-magic.deb
+], [2], [control.tar
+data.tar
+], [dpkg-deb: error: file 'pkg-missing-magic.deb' is not a Debian binary archive (try dpkg-split?)
+])
+
+AT_CHECK([
+# Test missing control member
+cp pkg-templ.deb pkg-missing-control.deb
+ar d pkg-missing-control.deb control.tar
+ar t pkg-missing-control.deb
+dpkg-deb -I pkg-missing-control.deb
+], [2], [debian-binary
+data.tar
+], [dpkg-deb: error: archive 'pkg-missing-control.deb' has premature member 'data.tar' before 'control.tar', giving up
+])
+
+AT_CHECK([
+# Test missing data member
+cp pkg-templ.deb pkg-missing-data.deb
+ar d pkg-missing-data.deb data.tar
+ar t pkg-missing-data.deb
+dpkg-deb -c pkg-missing-data.deb
+], [2], [debian-binary
+control.tar
+], [dpkg-deb: error: unexpected end of file in archive member header in pkg-missing-data.deb
+])
+
+AT_CHECK([
+# Test duplicate debian-binary member
+cp pkg-templ.deb pkg-duplicate-magic.deb
+ar ra debian-binary pkg-duplicate-magic.deb debian-binary debian-binary
+ar t pkg-duplicate-magic.deb
+dpkg-deb -I pkg-duplicate-magic.deb
+], [2], [debian-binary
+debian-binary
+control.tar
+data.tar
+], [dpkg-deb: error: archive 'pkg-duplicate-magic.deb' has premature member 'debian-binary' before 'control.tar', giving up
+])
+
+AT_CHECK([
+# Test duplicate control member
+cp pkg-templ.deb pkg-duplicate-control.deb
+ar ra control.tar pkg-duplicate-control.deb control.tar control.tar
+ar t pkg-duplicate-control.deb
+dpkg-deb -c pkg-duplicate-control.deb
+], [2], [debian-binary
+control.tar
+control.tar
+data.tar
+], [dpkg-deb: error: archive 'pkg-duplicate-control.deb' contains two control members, giving up
+])
+
+AT_CHECK([
+# Test mixed member (index 1)
+cp pkg-templ.deb pkg-mixed-1-member.deb
+ar ra debian-binary pkg-mixed-1-member.deb unknown
+ar t pkg-mixed-1-member.deb
+dpkg-deb -I pkg-mixed-1-member.deb
+], [2], [debian-binary
+unknown
+control.tar
+data.tar
+], [dpkg-deb: error: archive 'pkg-mixed-1-member.deb' has premature member 'unknown' before 'control.tar', giving up
+])
+
+AT_CHECK([
+# Test mixed member (index 2)
+cp pkg-templ.deb pkg-mixed-2-member.deb
+ar ra control.tar pkg-mixed-2-member.deb unknown
+ar t pkg-mixed-2-member.deb
+dpkg-deb -c pkg-mixed-2-member.deb
+], [2], [debian-binary
+control.tar
+unknown
+data.tar
+], [dpkg-deb: error: archive 'pkg-mixed-2-member.deb' has premature member 'unknown' before 'data.tar', giving up
+])
+
+AT_CHECK([
+# Test swapped control and data members
+cp pkg-templ.deb pkg-swap-members.deb
+ar ma data.tar pkg-swap-members.deb control.tar
+ar t pkg-swap-members.deb
+dpkg-deb -I pkg-swap-members.deb
+], [2], [debian-binary
+data.tar
+control.tar
+], [dpkg-deb: error: archive 'pkg-swap-members.deb' has premature member 'data.tar' before 'control.tar', giving up
+])
+
+AT_CHECK([
+# Test extra member
+cp pkg-templ.deb pkg-extra-member.deb
+ar q pkg-extra-member.deb unknown
+ar t pkg-extra-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-extra-member.deb | $SED -e 's/ *$//'
+], [], [debian-binary
+control.tar
+data.tar
+unknown
+ new Debian package, version 2.0.
+ size 655612 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+])
+
+AT_CHECK([
+# Test _ member
+cp pkg-templ.deb pkg-under-member.deb
+ar ra debian-binary pkg-under-member.deb _ignore
+ar t pkg-under-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-under-member.deb | $SED -e 's/ *$//'
+], [], [debian-binary
+_ignore
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655612 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+])
+
+AT_CHECK([
+# Test data.tar.bad member
+dd if=/dev/zero of=data.tar.bad bs=1K count=4 status=none
+ar rc pkg-data-bad.deb debian-binary control.tar.gz data.tar.bad
+ar t pkg-data-bad.deb
+dpkg-deb -c pkg-data-bad.deb
+], [2], [debian-binary
+control.tar.gz
+data.tar.bad
+], [dpkg-deb: error: archive 'pkg-data-bad.deb' uses unknown compression for member 'data.tar.bad', giving up
+])
+
+AT_CHECK([
+# Test control.tar member
+ar rc pkg-control-none.deb debian-binary control.tar data.tar
+ar t pkg-control-none.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-control-none.deb | $SED -e 's/ *$//'
+], [], [debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655552 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+])
+
+AT_CHECK([
+# Test control.tar.xz member
+ar rc pkg-control-xz.deb debian-binary control.tar.xz data.tar.xz
+ar t pkg-control-xz.deb
+dpkg-deb -c pkg-control-xz.deb
+], [], [debian-binary
+control.tar.xz
+data.tar.xz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test control.tar.zst member
+ar rc pkg-control-zst.deb debian-binary control.tar.zst data.tar.zst
+ar t pkg-control-zst.deb
+dpkg-deb -c pkg-control-zst.deb
+], [], [debian-binary
+control.tar.zst
+data.tar.zst
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar member
+ar rc pkg-data-none.deb debian-binary control.tar.gz data.tar
+ar t pkg-data-none.deb
+dpkg-deb -c pkg-data-none.deb
+], [], [debian-binary
+control.tar.gz
+data.tar
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar.gz member
+ar rc pkg-data-gz.deb debian-binary control.tar.gz data.tar.gz
+ar t pkg-data-gz.deb
+dpkg-deb -c pkg-data-gz.deb
+], [], [debian-binary
+control.tar.gz
+data.tar.gz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar.xz member
+ar rc pkg-data-xz.deb debian-binary control.tar.gz data.tar.xz
+ar t pkg-data-xz.deb
+dpkg-deb -c pkg-data-xz.deb
+], [], [debian-binary
+control.tar.gz
+data.tar.xz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar.zst member
+ar rc pkg-data-zst.deb debian-binary control.tar.gz data.tar.zst
+ar t pkg-data-zst.deb
+dpkg-deb -c pkg-data-zst.deb
+], [], [debian-binary
+control.tar.gz
+data.tar.zst
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar.bz2 member
+ar rc pkg-data-bz2.deb debian-binary control.tar.gz data.tar.bz2
+ar t pkg-data-bz2.deb
+dpkg-deb -c pkg-data-bz2.deb
+], [], [debian-binary
+control.tar.gz
+data.tar.bz2
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test data.tar.lzma member
+ar rc pkg-data-lzma.deb debian-binary control.tar.gz data.tar.lzma
+ar t pkg-data-lzma.deb
+dpkg-deb -c pkg-data-lzma.deb
+], [], [debian-binary
+control.tar.gz
+data.tar.lzma
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test non-uniform data.tar/control.tar member compression
+ar rc pkg-mixed-comp.deb debian-binary control.tar.xz data.tar.gz
+ar t pkg-mixed-comp.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-mixed-comp.deb | $SED -e 's/ *$//'
+dpkg-deb -c pkg-mixed-comp.deb
+], [], [debian-binary
+control.tar.xz
+data.tar.gz
+ new Debian package, version 2.0.
+ size 175756 bytes: control archive=336 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+])
+
+AT_CHECK([
+# Test building and extracting none compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ pkg-comp-none.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-none.deb >ctrl-none.tar
+dpkg-deb --fsys-tarfile pkg-comp-none.deb >fsys-none.tar
+cmp ctrl-none.tar control.tar
+cmp fsys-none.tar data.tar
+])
+
+AT_CHECK([
+# Test building and extracting gzip compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zgzip -b pkg-templ pkg-comp-gzip.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-gzip.deb >ctrl-gzip.tar
+dpkg-deb --fsys-tarfile pkg-comp-gzip.deb >fsys-gzip.tar
+cmp ctrl-gzip.tar control.tar
+cmp fsys-gzip.tar data.tar
+])
+
+AT_CHECK([
+# Test building and extracting xz compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zxz -b pkg-templ pkg-comp-xz.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-xz.deb >ctrl-xz.tar
+dpkg-deb --fsys-tarfile pkg-comp-xz.deb >fsys-xz.tar
+cmp ctrl-xz.tar control.tar
+cmp fsys-xz.tar data.tar
+])
+
+AT_CHECK([
+# Test building and extracting zstd compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zzstd -b pkg-templ pkg-comp-zstd.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-zstd.deb >ctrl-zstd.tar
+dpkg-deb --fsys-tarfile pkg-comp-zstd.deb >fsys-zstd.tar
+cmp ctrl-zstd.tar control.tar
+cmp fsys-zstd.tar data.tar
+])
+
+AT_CLEANUP
diff --git a/src/at/deb-split.at b/src/at/deb-split.at
new file mode 100644
index 0000000..6b07d79
--- /dev/null
+++ b/src/at/deb-split.at
@@ -0,0 +1,228 @@
+AT_SETUP([dpkg-split options])
+AT_KEYWORDS([dpkg-split command-line])
+
+AT_CHECK([dpkg-split --version], [], [ignore])
+AT_CHECK([dpkg-split --help], [], [ignore])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-split .deb format])
+AT_KEYWORDS([dpkg-split deb-split])
+
+DPKG_GEN_CONTROL([pkg-split])
+DPKG_MOD_CONTROL([pkg-split],
+ [s/^Description:.*$/& - normal package to be split/])
+AT_CHECK([
+# Initialize the template package
+chmod -R u+w pkg-split
+$PERL -E 'print "fade" foreach 1 .. 1024 * 512' >pkg-split/data-file
+find pkg-split | xargs touch -t 197001010100.00
+dpkg-deb --root-owner-group -Znone -b pkg-split >/dev/null
+])
+
+AT_CHECK([
+# Test splitting a package (in 10 parts: 9 * 210 KiB B + 158 KiB)
+dpkg-split -S 210 -s pkg-split.deb pkg-split-part
+for p in $(seq 10); do
+ test -f pkg-split-part.${p}of10.deb
+done
+], [], [Splitting package pkg-split into 10 parts: 1 2 3 4 5 6 7 8 9 10 done
+])
+
+DEB_SPLIT_MD5SUM=1684b6cdb72bf035ccafd653f307d3da
+DEB_SPLIT_LENGTH=2109632
+DEB_SPLIT_PART_LENGTH=214016
+DEB_SPLIT_PART_SIZE=214222
+DEB_SPLIT_LAST_LENGTH=183488
+DEB_SPLIT_LAST_SIZE=183694
+
+DEB_SPLIT_PART_SIZE_VERSION=$((DEB_SPLIT_PART_SIZE + 2))
+
+AT_CHECK_UNQUOTED([
+# Test debian-split with 2.x version
+cp pkg-split-part.1of10.deb pkg-split-part-version-2x.deb
+ar x pkg-split-part-version-2x.deb debian-split
+sed -e '1c2.999' debian-split >debian-split.new
+mv debian-split.new debian-split
+ar rc pkg-split-part-version-2x.deb debian-split
+ar t pkg-split-part-version-2x.deb
+dpkg-split -I pkg-split-part-version-2x.deb
+], [], [debian-split
+data.1
+pkg-split-part-version-2x.deb:
+ Part format version: 2.999
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE_VERSION bytes
+
+])
+
+DEB_SPLIT_PART_SIZE_MAGIC_EXTRA=$((DEB_SPLIT_PART_SIZE + 10))
+
+AT_CHECK_UNQUOTED([
+# Test debian-split with extra lines
+cp pkg-split-part.1of10.deb pkg-split-part-magic-extra.deb
+ar x pkg-split-part-magic-extra.deb debian-split
+echo "extra line" >>debian-split
+ar rc pkg-split-part-magic-extra.deb debian-split
+ar t pkg-split-part-magic-extra.deb
+dpkg-split -I pkg-split-part-magic-extra.deb
+], [], [debian-split
+data.1
+pkg-split-part-magic-extra.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE_MAGIC_EXTRA bytes
+
+])
+
+AT_CHECK([
+# Test missing debian-split
+cp pkg-split-part.1of10.deb pkg-split-part-missing-magic.deb
+ar d pkg-split-part-missing-magic.deb debian-split
+ar t pkg-split-part-missing-magic.deb
+dpkg-split -I pkg-split-part-missing-magic.deb
+], [], [data.1
+file 'pkg-split-part-missing-magic.deb' is not an archive part
+])
+
+AT_CHECK([
+# Test missing data part member
+cp pkg-split-part.1of10.deb pkg-split-part-missing-data.deb
+ar d pkg-split-part-missing-data.deb data.1
+ar t pkg-split-part-missing-data.deb
+dpkg-split -I pkg-split-part-missing-data.deb
+], [2], [debian-split
+], [dpkg-split: error: unexpected end of file in reading data part member ar header in pkg-split-part-missing-data.deb
+])
+
+AT_CHECK([
+# Test duplicate debian-split member
+cp pkg-split-part.1of10.deb pkg-split-part-duplicate-magic.deb
+ar x pkg-split-part-duplicate-magic.deb debian-split
+ar ra debian-split pkg-split-part-duplicate-magic.deb debian-split debian-split
+ar t pkg-split-part-duplicate-magic.deb
+dpkg-split -I pkg-split-part-duplicate-magic.deb
+], [2], [debian-split
+debian-split
+data.1
+], [dpkg-split: error: file 'pkg-split-part-duplicate-magic.deb' is corrupt - second member is not data member
+])
+
+AT_CHECK_UNQUOTED([
+# Test unknown extra member
+cp pkg-split-part.1of10.deb pkg-split-part-extra-member.deb
+echo "some content" >unknown
+ar q pkg-split-part-extra-member.deb unknown
+ar t pkg-split-part-extra-member.deb
+dpkg-split -I pkg-split-part-extra-member.deb
+], [], [debian-split
+data.1
+unknown
+pkg-split-part-extra-member.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+])
+
+AT_CHECK_UNQUOTED([
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.1of10.deb
+], [], [pkg-split-part.1of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+])
+AT_CHECK_UNQUOTED([
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.2of10.deb
+], [], [pkg-split-part.2of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 2/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 214016 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+])
+AT_CHECK_UNQUOTED([
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.9of10.deb
+], [], [pkg-split-part.9of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 9/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 1712128 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+])
+AT_CHECK_UNQUOTED([
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.10of10.deb
+], [], [pkg-split-part.10of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 10/10
+ Part length: $DEB_SPLIT_LAST_LENGTH bytes
+ Part offset: 1926144 bytes
+ Part file size (used portion): $DEB_SPLIT_LAST_SIZE bytes
+
+])
+
+AT_CHECK([
+# Test joining the split parts back together
+dpkg-split -o pkg-joined.deb -j pkg-split-part.*.deb
+cmp pkg-split.deb pkg-joined.deb
+], [], [Putting package pkg-split together from 10 parts: 1 2 3 4 5 6 7 8 9 10 done
+])
+
+AT_CLEANUP
diff --git a/src/at/divert.at b/src/at/divert.at
new file mode 100644
index 0000000..f8689d0
--- /dev/null
+++ b/src/at/divert.at
@@ -0,0 +1,639 @@
+AT_SETUP([dpkg-divert options])
+AT_KEYWORDS([dpkg-divert command-line])
+
+DPKG_GEN_FSYS_DIR([/testdir])
+
+AT_CHECK([dpkg-divert --version], [], [ignore])
+AT_CHECK([dpkg-divert --help], [], [ignore])
+
+AT_CHECK([dpkg-divert --admindir], [2], [], [stderr])
+AT_CHECK([grep -qE '(takes a value|needs.*argument)' stderr])
+
+AT_CHECK([DPKG_DIVERT --jachsmitbju], [2], [], [stderr])
+AT_CHECK([grep -q 'unknown option' stderr])
+
+AT_CHECK([DPKG_DIVERT --add --remove], [2], [], [stderr])
+AT_CHECK([grep -qE '(conflicting|two).*remove.*add.*' stderr])
+
+AT_CHECK([DPKG_DIVERT --divert], [2], [], [stderr])
+AT_CHECK([grep -qE '(takes a value|needs.*argument)' stderr])
+
+AT_CHECK([DPKG_DIVERT --divert foo], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --divert "/foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CHECK([DPKG_DIVERT --package], [2], [], [stderr])
+AT_CHECK([grep -qE '(takes a value|needs.*argument)' stderr])
+
+AT_CHECK([DPKG_DIVERT --package "foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CHECK([DPKG_DIVERT --add], [2], [], [stderr])
+AT_CHECK([grep -q 'needs a single argument' stderr])
+
+AT_CHECK([DPKG_DIVERT --add foo], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --add "/foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CHECK([DPKG_DIVERT --add "/testdir"], [2], [], [stderr])
+AT_CHECK([grep -qE 'director(y|ies)' stderr])
+
+AT_CHECK([DPKG_DIVERT --add --divert bar /foo/bar], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --remove], [2], [], [stderr])
+AT_CHECK([grep -q 'needs a single argument' stderr])
+
+AT_CHECK([DPKG_DIVERT --remove foo], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --remove "/foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CHECK([DPKG_DIVERT --listpackage], [2], [], [stderr])
+AT_CHECK([grep -q 'needs a single argument' stderr])
+
+AT_CHECK([DPKG_DIVERT --listpackage foo], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --listpackage "/foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CHECK([DPKG_DIVERT --truename], [2], [], [stderr])
+AT_CHECK([grep -q 'needs a single argument' stderr])
+
+AT_CHECK([DPKG_DIVERT --truename foo], [2], [], [stderr])
+AT_CHECK([grep -q 'absolute' stderr])
+
+AT_CHECK([DPKG_DIVERT --truename "/foo
+bar"], [2], [], [stderr])
+AT_CHECK([grep -q 'newline' stderr])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert query (empty db)])
+AT_KEYWORDS([dpkg-divert query])
+
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --list])
+AT_CHECK([DPKG_DIVERT --list '*'])
+AT_CHECK([DPKG_DIVERT --list 'baz'])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert query (list)])
+AT_KEYWORDS([dpkg-divert query])
+
+DPKG_GEN_DB_DIVERSIONS([/bin/sh
+/bin/sh.distrib
+dash
+/usr/share/man/man1/sh.1.gz
+/usr/share/man/man1/sh.distrib.1.gz
+dash
+/usr/bin/nm
+/usr/bin/nm.single
+binutils-multiarch
+])
+
+m4_define([di_dash], [diversion of /bin/sh to /bin/sh.distrib by dash
+])
+m4_define([di_dashman],
+ [diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+])
+m4_define([di_nm],
+ [diversion of /usr/bin/nm to /usr/bin/nm.single by binutils-multiarch
+])
+m4_define([all_di], [m4_join([], di_nm, di_dashman, di_dash)])
+
+AT_CHECK([DPKG_DIVERT --list], [], all_di)
+AT_CHECK([DPKG_DIVERT --list '*'], [], all_di)
+AT_CHECK([DPKG_DIVERT --list ''])
+
+AT_CHECK([DPKG_DIVERT --list '???????'], [], di_dash)
+AT_CHECK([DPKG_DIVERT --list '*/sh'], [], di_dash)
+AT_CHECK([DPKG_DIVERT --list '/bin/*'], [], di_dash)
+AT_CHECK([DPKG_DIVERT --list binutils-multiarch], [], di_nm)
+AT_CHECK([DPKG_DIVERT --list /bin/sh], [], di_dash)
+AT_CHECK([DPKG_DIVERT --list -- /bin/sh], [], di_dash)
+AT_CHECK([DPKG_DIVERT --list /usr/bin/nm.single], [], di_nm)
+AT_CHECK([DPKG_DIVERT --list /bin/sh /usr/share/man/man1/sh.1.gz], [],
+ [m4_join([], di_dashman, di_dash)])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert query (listpackage + truename)])
+AT_KEYWORDS([dpkg-divert query])
+
+DPKG_GEN_DB_DIVERSIONS([/bin/sh
+/bin/sh.distrib
+dash
+/bin/true
+/bin/true.coreutils
+:
+])
+
+AT_CHECK([DPKG_DIVERT --listpackage /bin/sh], [], [dash
+])
+AT_CHECK([DPKG_DIVERT --listpackage /bin/true], [], [LOCAL
+])
+AT_CHECK([DPKG_DIVERT --listpackage /bin/false])
+
+AT_CHECK([DPKG_DIVERT --truename /bin/sh], [], [/bin/sh.distrib
+])
+AT_CHECK([DPKG_DIVERT --truename /bin/sh.distrib], [], [/bin/sh.distrib
+])
+AT_CHECK([DPKG_DIVERT --truename /bin/something], [], [/bin/something
+])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (local rename)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q "Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib" stdout])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (local no-rename)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --no-rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q "Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib" stdout])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename quiet)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --add /testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (test rename quiet)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --test /testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo.distrib])
+AT_CHECK([cat DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename missing quiet)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_DIR([/testdir])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename /testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (local rename quiet)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --local --rename /testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (package rename quiet)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+bash
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --package bash /testdir/foo])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename self-link)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_FSYS_LINK([/testdir/foo], [/testdir/foo.distrib])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename /testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename other-file)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_FSYS_FILE([/testdir/foo.distrib], [])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename /testdir/foo], [2], [], [stderr])
+AT_CHECK([grep -q 'error: rename involves overwriting' stderr])
+AT_CHECK([cat DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename missing dir)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/zoo/foo
+/testdir/zoo/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --add /testdir/zoo/foo])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename read-only dir)])
+AT_KEYWORDS([dpkg-divert fsys])
+
+AT_SKIP_IF([test -n "$FAKEROOTKEY" || test "$(id -u)" = 0])
+
+DPKG_GEN_FSYS_DIR([/testdir/rodir])
+DPKG_GEN_FSYS_FILE([/testdir/rodir/foo])
+DPKG_GEN_FSYS_FILE([/testdir/bar])
+DPKG_MOD_FSYS_MODE([500], [/testdir/rodir])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --add /testdir/rodir/foo],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'error: .* Permission denied' stderr])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --divert /testdir/rodir/bar --add /testdir/bar],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'error: .* Permission denied' stderr])
+
+AT_CHECK([cat DPKG_DIR_ADMIN/diversions])
+
+DPKG_MOD_FSYS_MODE([755], [/testdir/rodir])
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (rename no-access dir)])
+AT_KEYWORDS([dpkg-divert fsys])
+
+AT_SKIP_IF([test -n "$FAKEROOTKEY" || test "$(id -u)" = 0])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo])
+DPKG_GEN_FSYS_DIR([/testdir/nadir])
+DPKG_MOD_FSYS_MODE([000], [/testdir/nadir])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/nadir/foo], [2], [], [stderr])
+AT_CHECK([grep -q 'error: .* Permission denied' stderr])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --divert /testdir/nadir/foo --add /testdir/foo],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'error: .* Permission denied' stderr])
+
+AT_CHECK([cat DPKG_DIR_ADMIN/diversions])
+
+# On FreeBSD «rm -rf» cannot traverse a directory with mode 000.
+rmdir DPKG_DIR_INST/testdir/nadir
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add second diversion])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_DIR([/testdir])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Adding' stdout])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Leaving' stdout])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Leaving' stdout])
+
+AT_CHECK([DPKG_DIVERT --divert /testdir/foo.bar /testdir/foo],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CHECK([DPKG_DIVERT --package foobar /testdir/foo], [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CHECK([DPKG_DIVERT --divert /testdir/foo.distrib /testdir/bar],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CHECK([DPKG_DIVERT /testdir/foo.distrib], [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CHECK([DPKG_DIVERT --divert /testdir/foo /testdir/bar], [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add third diversion])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_DIR([/testdir])
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Adding' stdout])
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/bar], [], [stdout])
+AT_CHECK([grep -q 'Adding' stdout])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Leaving' stdout])
+AT_CHECK([DPKG_DIVERT --rename --package foobar --add /testdir/bar],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'clashes' stderr])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert add (file owned by --package)])
+AT_KEYWORDS([dpkg-divert add])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+# Only installed packages have their files list considered.
+DPKG_GEN_DB_STATUS([Package: coreutils
+Status: install ok installed
+Version: 0
+Architecture: i386
+Maintainer: dummy
+Description: dummy
+])
+DPKG_GEN_DB_INFO_FILE([coreutils], [list], [/testdir/foo
+])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+coreutils
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --package coreutils --add /testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert remove (missing)])
+AT_KEYWORDS([dpkg-divert remove])
+
+DPKG_GEN_DB_DIVERSIONS([])
+
+AT_CHECK([DPKG_DIVERT --no-rename --remove /bin/sh], [], [stdout])
+AT_CHECK([grep -q 'No diversion' stdout])
+
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --remove /bin/sh])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert remove (divert-to)])
+AT_KEYWORDS([dpkg-divert remove])
+
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/bar
+/testdir/bar.distrib
+:
+/testdir/baz
+/testdir/baz.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/foo])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/bar])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/baz])
+
+AT_CHECK([DPKG_DIVERT --divert /testdir/foo.my --remove /testdir/foo],
+ [2], [], [stderr])
+AT_CHECK([grep -q 'mismatch on divert-to' stderr])
+
+AT_CHECK([DPKG_DIVERT --package baz --remove /testdir/foo], [2], [], [stderr])
+AT_CHECK([grep -q 'mismatch on package' stderr])
+
+AT_CHECK([DPKG_DIVERT --package baz --divert /testdir/foo.my --remove /testdir/foo],
+ [2], [], [stderr])
+AT_CHECK([grep -qE 'mismatch on (package|divert-to)' stderr])
+
+AT_CHECK([DPKG_DIVERT --rename --divert /testdir/foo.distrib --remove /testdir/foo],
+ [], [stdout])
+AT_CHECK([grep -qE 'Removing .*/testdir/foo' stdout])
+
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert remove (plain)])
+AT_KEYWORDS([dpkg-divert remove])
+
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+/testdir/baz
+/testdir/baz.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/foo])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/bar])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --add /testdir/baz])
+
+AT_CHECK([DPKG_DIVERT --no-rename --remove /testdir/bar], [], [stdout])
+AT_CHECK([grep -qE 'Removing .* /testdir/bar' stdout])
+
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert remove (by-package)])
+AT_KEYWORDS([dpkg-divert remove])
+
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/bar
+/testdir/bar.distrib
+:
+/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --no-rename /testdir/foo])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename /testdir/bar])
+AT_CHECK([DPKG_DIVERT --quiet --no-rename --package bash /testdir/baz])
+
+AT_CHECK([DPKG_DIVERT --no-rename --quiet --package bash --remove /testdir/baz])
+
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert remove (test)])
+AT_KEYWORDS([dpkg-divert remove])
+
+DPKG_GEN_FSYS_FILE([/testdir/foo], [])
+DPKG_GEN_DB_DIVERSIONS([])
+AT_DATA([ref-diversions], [/testdir/foo
+/testdir/foo.distrib
+:
+])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename /testdir/foo])
+
+AT_CHECK([DPKG_DIVERT --test --rename --remove /testdir/foo], [], [stdout])
+AT_CHECK([grep -q 'Removing .*/testdir/foo' stdout])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo.distrib])
+AT_CHECK([diff -u ref-diversions DPKG_DIR_ADMIN/diversions])
+
+AT_CHECK([DPKG_DIVERT --quiet --rename --remove /testdir/foo])
+DPKG_CHECK_FSYS_PATH_EXISTS([/testdir/foo])
+DPKG_CHECK_FSYS_PATH_MISSING([/testdir/foo.distrib])
+AT_CHECK([cat DPKG_DIR_ADMIN/diversions])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert db (no-access)])
+AT_KEYWORDS([dpkg-divert db])
+
+AT_SKIP_IF([test -n "$FAKEROOTKEY" || test "$(id -u)" = 0])
+
+# An inexistent diversions db file should not be considered a failure,
+# but a failure to open it should be.
+DPKG_GEN_DB_DIVERSIONS([])
+DPKG_MOD_DB_MODE([000], [diversions])
+
+AT_CHECK([DPKG_DIVERT --list], [2], [], [stderr])
+AT_CHECK([grep -qE '(cannot|failed).*open' stderr])
+
+DPKG_MOD_DB_MODE([644], [diversions])
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert db (truncated)])
+AT_KEYWORDS([dpkg-divert db])
+
+DPKG_GEN_DB_DIVERSIONS([/bin/sh
+])
+
+AT_CHECK([DPKG_DIVERT --list], [2], [], [stderr])
+AT_CHECK([grep -qE '(corrupt|unexpected end of file)' stderr])
+
+DPKG_GEN_DB_DIVERSIONS([/bin/sh
+bash
+])
+
+AT_CHECK([DPKG_DIVERT --list], [2], [], [stderr])
+AT_CHECK([grep -qE '(corrupt|unexpected end of file)' stderr])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert db (read-only dir)])
+AT_KEYWORDS([dpkg-divert db])
+
+AT_SKIP_IF([test -n "$FAKEROOTKEY" || test "$(id -u)" = 0])
+
+DPKG_GEN_DB_DIVERSIONS([])
+DPKG_MOD_DB_MODE([500])
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [2], [stdout], [stderr])
+AT_CHECK([grep -q 'Adding' stdout])
+AT_CHECK([grep -q 'create.*new' stderr])
+
+DPKG_MOD_DB_MODE([755])
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert db (disk full)])
+AT_KEYWORDS([dpkg-divert db])
+
+AT_SKIP_IF([test -n "$FAKEROOTKEY" || test "$(id -u)" = 0])
+AT_SKIP_IF([! test -c /dev/full])
+
+DPKG_GEN_DB_DIVERSIONS([])
+ln -s /dev/full DPKG_DIR_ADMIN/diversions-new
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [2], [stdout], [stderr])
+AT_CHECK([grep -q 'Adding' stdout])
+AT_CHECK([grep -qE '(write|flush|close).*new' stderr])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-divert db (pathname is dir)])
+AT_KEYWORDS([dpkg-divert db])
+
+DPKG_GEN_DB_DIVERSIONS([])
+rm -f DPKG_DIR_ADMIN/diversions-new
+mkdir DPKG_DIR_ADMIN/diversions-old
+
+AT_CHECK([DPKG_DIVERT --rename --add /testdir/foo], [2], [stdout], [stderr])
+AT_CHECK([grep -q 'Adding' stdout])
+AT_CHECK([grep -q 'remov.*old' stderr])
+
+AT_CLEANUP
diff --git a/src/at/local.at b/src/at/local.at
new file mode 100644
index 0000000..1def684
--- /dev/null
+++ b/src/at/local.at
@@ -0,0 +1,132 @@
+# Dpkg helper macros
+
+m4_pattern_forbid([^DPKG_])
+m4_pattern_allow([^DPKG_DEBUG$])
+m4_pattern_allow([^DPKG_ROOT$])
+m4_pattern_allow([^DPKG_ADMINDIR$])
+m4_pattern_allow([^DPKG_DATADIR$])
+
+#
+# Options.
+#
+
+m4_define([DPKG_DIR_INST], [dpkginst])
+m4_define([DPKG_DIR_ADMIN], [dpkgdb])
+
+# DPKG_OPTIONS_COMMON
+m4_define([DPKG_OPTIONS_COMMON], [dnl
+ --admindir=DPKG_DIR_ADMIN dnl
+])
+
+# DPKG_DIVERT_OPTIONS
+m4_define([DPKG_DIVERT_OPTIONS], [dnl
+ --instdir=DPKG_DIR_INST dnl
+])
+
+# DPKG_DIVERT(...)
+m4_define([DPKG_DIVERT],
+ [dpkg-divert DPKG_OPTIONS_COMMON DPKG_DIVERT_OPTIONS])
+
+# DPKG_DIVERT_ADD(...)
+m4_define([DPKG_DIVERT_ADD], [DPKG_DIVERT --add])
+
+# DPKG_DIVERT_DEL(...)
+m4_define([DPKG_DIVERT_DEL], [DPKG_DIVERT --remove])
+
+#
+# Macros.
+#
+
+# DPKG_FILE_SIZE()
+m4_define([DPKG_FILE_SIZE], [
+ $PERL -E 'say -s shift' "$1" dnl
+])
+
+# DPKG_GEN_FSYS()
+m4_define([DPKG_GEN_DB], [
+ mkdir -p DPKG_DIR_INST
+])
+
+# DPKG_GEN_FSYS_DIR([$dirname])
+m4_define([DPKG_GEN_FSYS_DIR], [
+ mkdir -p "DPKG_DIR_INST/$1"
+])
+
+# DPKG_GEN_FSYS_FILE([$filename], [$contents])
+m4_define([DPKG_GEN_FSYS_FILE], [
+ mkdir -p "DPKG_DIR_INST/$(dirname '$1')"
+ AT_DATA([DPKG_DIR_INST/$1], [$2])
+])
+
+# DPKG_GEN_FSYS_LINK([$pathname], [$target])
+m4_define([DPKG_GEN_FSYS_LINK], [
+ ln "DPKG_DIR_INST/$1" "DPKG_DIR_INST/$2"
+])
+
+# DPKG_CHECK_FSYS_PATH_EXISTS([$pathname])
+m4_define([DPKG_CHECK_FSYS_PATH_EXISTS], [
+ AT_CHECK([test -e "DPKG_DIR_INST/$1"])
+])
+
+# DPKG_CHECK_FSYS_PATH_MISSING([$pathname])
+m4_define([DPKG_CHECK_FSYS_PATH_MISSING], [
+ AT_CHECK([test -e "DPKG_DIR_INST/$1"], [1])
+])
+
+# DPKG_MOD_FSYS_MODE([$mode], [$pathname])
+m4_define([DPKG_MOD_FSYS_MODE], [
+ chmod $1 "DPKG_DIR_INST/$2"
+])
+
+# DPKG_TMPL_CONTROL([$pkgname])
+m4_define([DPKG_TMPL_CONTROL],
+[Package: $1
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package])
+
+# DPKG_GEN_DB_STATUS([$contents])
+m4_define([DPKG_GEN_DB_STATUS], [
+ mkdir -p "DPKG_DIR_ADMIN"
+ AT_DATA([DPKG_DIR_ADMIN/status], [$1])
+])
+
+# DPKG_GEN_DB_DIVERSIONS([$contents])
+m4_define([DPKG_GEN_DB_DIVERSIONS], [
+ mkdir -p "DPKG_DIR_ADMIN"
+ AT_DATA([DPKG_DIR_ADMIN/diversions], [$1])
+])
+
+# DPKG_GEN_DB_INFO_FILE([$pkg], [$file], [$contents])
+m4_define([DPKG_GEN_DB_INFO_FILE], [
+ mkdir -p "DPKG_DIR_ADMIN/info"
+ AT_DATA([DPKG_DIR_ADMIN/info/$1.$2], [$3])
+])
+
+# DPKG_MOD_DB_MODE([$mode], [$pathname])
+m4_define([DPKG_MOD_DB_MODE], [
+ chmod $1 "DPKG_DIR_ADMIN/$2"
+])
+
+# DPKG_GEN_CTRL_FILE([$pkgname], [$file], [$contents])
+m4_define([DPKG_GEN_CTRL_FILE], [
+ mkdir -p '$1/DEBIAN'
+
+ cat >'$1/DEBIAN/$2' <<CTRL_TEMPL
+$3
+CTRL_TEMPL
+])
+
+# DPKG_GEN_CONTROL([$pkgname])
+m4_define([DPKG_GEN_CONTROL], [
+ DPKG_GEN_CTRL_FILE([$1], [control], [DPKG_TMPL_CONTROL([$1])])
+])
+
+# DPKG_MOD_CONTROL([$pkgname], [$sedexpr])
+m4_define([DPKG_MOD_CONTROL], [
+ $SED -e '$2' <'$1/DEBIAN/control' >'$1/DEBIAN/control.new'
+ mv '$1/DEBIAN/control.new' '$1/DEBIAN/control'
+])
diff --git a/src/at/package.m4 b/src/at/package.m4
new file mode 100644
index 0000000..37a97d6
--- /dev/null
+++ b/src/at/package.m4
@@ -0,0 +1,7 @@
+# Signature of the current package.
+m4_define([AT_PACKAGE_NAME], [dpkg])
+m4_define([AT_PACKAGE_TARNAME], [dpkg])
+m4_define([AT_PACKAGE_VERSION], [1.21.22])
+m4_define([AT_PACKAGE_STRING], [dpkg 1.21.22])
+m4_define([AT_PACKAGE_URL], [https://wiki.debian.org/Teams/Dpkg])
+m4_define([AT_PACKAGE_BUGREPORT], [debian-dpkg@lists.debian.org])
diff --git a/src/at/realpath.at b/src/at/realpath.at
new file mode 100644
index 0000000..2919c3e
--- /dev/null
+++ b/src/at/realpath.at
@@ -0,0 +1,86 @@
+AT_SETUP([dpkg-realpath options])
+AT_KEYWORDS([dpkg-realpath command-line])
+
+AT_CHECK([dpkg-realpath --version], [], [ignore])
+AT_CHECK([dpkg-realpath --help], [], [ignore])
+
+AT_CLEANUP
+
+AT_SETUP([dpkg-realpath path resolving])
+AT_KEYWORDS([dpkg-realpath canonicalize])
+
+mkdir -p aa/bb/cc
+mkdir -p zz/yy/xx
+mkdir -p usr/bin
+AT_DATA([aa/bb/cc/file], [])
+ln -sfT aa/bb/cc/file zz/yy/xx/symlink-rel
+ln -sfT /aa/bb/cc/file zz/yy/xx/symlink-abs
+AT_DATA([usr/bin/a-shell], [])
+ln -sfT /usr/bin/a-shell usr/bin/sh
+
+tmpdir="$(pwd)"
+export DPKG_ROOT=
+
+# Relative paths
+AT_CHECK_UNQUOTED([dpkg-realpath aa/bb/cc], [],
+[$tmpdir/aa/bb/cc
+])
+AT_CHECK_UNQUOTED([dpkg-realpath zz/yy/xx], [], [$tmpdir/zz/yy/xx
+])
+AT_CHECK_UNQUOTED([dpkg-realpath usr/bin], [], [$tmpdir/usr/bin
+])
+AT_CHECK_UNQUOTED([dpkg-realpath aa/bb/cc/file], [], [$tmpdir/aa/bb/cc/file
+])
+AT_CHECK_UNQUOTED([dpkg-realpath zz/yy/xx/symlink-rel], [],
+[$tmpdir/zz/yy/xx/aa/bb/cc/file
+])
+AT_CHECK([dpkg-realpath zz/yy/xx/symlink-abs], [], [/aa/bb/cc/file
+])
+AT_CHECK_UNQUOTED([dpkg-realpath usr/bin/a-shell], [],
+[$tmpdir/usr/bin/a-shell
+])
+AT_CHECK([dpkg-realpath usr/bin/sh], [], [/usr/bin/a-shell
+])
+
+# Absolute paths
+cd /
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/aa/bb/cc"], [], [$tmpdir/aa/bb/cc
+])
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/zz/yy/xx"], [], [$tmpdir/zz/yy/xx
+])
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/usr/bin"], [], [$tmpdir/usr/bin
+])
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/aa/bb/cc/file"], [],
+[$tmpdir/aa/bb/cc/file
+])
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/zz/yy/xx/symlink-rel"], [],
+[$tmpdir/zz/yy/xx/aa/bb/cc/file
+])
+AT_CHECK([dpkg-realpath "$tmpdir/zz/yy/xx/symlink-abs"], [], [/aa/bb/cc/file
+])
+AT_CHECK_UNQUOTED([dpkg-realpath "$tmpdir/usr/bin/a-shell"], [],
+[$tmpdir/usr/bin/a-shell
+])
+AT_CHECK([dpkg-realpath "$tmpdir/usr/bin/sh"], [], [/usr/bin/a-shell
+])
+
+# Chrooted paths
+DPKG_ROOT="$tmpdir"
+AT_CHECK([dpkg-realpath /aa/bb/cc], [], [/aa/bb/cc
+])
+AT_CHECK([dpkg-realpath /zz/yy/xx], [], [/zz/yy/xx
+])
+AT_CHECK([dpkg-realpath /usr/bin], [], [/usr/bin
+])
+AT_CHECK([dpkg-realpath /aa/bb/cc/file], [], [/aa/bb/cc/file
+])
+AT_CHECK([dpkg-realpath /zz/yy/xx/symlink-rel], [], [/zz/yy/xx/aa/bb/cc/file
+])
+AT_CHECK([dpkg-realpath /zz/yy/xx/symlink-abs], [], [/aa/bb/cc/file
+])
+AT_CHECK([dpkg-realpath /usr/bin/a-shell], [], [/usr/bin/a-shell
+])
+AT_CHECK([dpkg-realpath /usr/bin/sh], [], [/usr/bin/a-shell
+])
+
+AT_CLEANUP
diff --git a/src/at/testsuite b/src/at/testsuite
new file mode 100755
index 0000000..57fc1fb
--- /dev/null
+++ b/src/at/testsuite
@@ -0,0 +1,12702 @@
+#! /bin/sh
+# Generated from testsuite.at by GNU Autoconf 2.71.
+#
+# Copyright (C) 2009-2017, 2020-2021 Free Software Foundation, Inc.
+#
+# This test suite is free software; the Free Software Foundation gives
+# unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else $as_nop
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
+as_nl='
+'
+export as_nl
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
+
+# The user is always right.
+if ${PATH_SEPARATOR+false} :; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="as_nop=:
+if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else \$as_nop
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" )
+then :
+
+else \$as_nop
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+blah=\$(echo \$(echo blah))
+test x\"\$blah\" = xblah || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null
+then :
+ as_have_required=yes
+else $as_nop
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
+then :
+
+else $as_nop
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
+then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi
+fi
+
+
+ if test "x$CONFIG_SHELL" != x
+then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno
+then :
+ printf "%s\n" "$0: This script requires a shell more modern than all"
+ printf "%s\n" "$0: the shells that I found on your system."
+ if test ${ZSH_VERSION+y} ; then
+ printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+printf "%s\n" X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else $as_nop
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else $as_nop
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ printf "%s\n" "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+printf "%s\n" X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# How were we run?
+at_cli_args="$@"
+
+
+# Not all shells have the 'times' builtin; the subshell is needed to make
+# sure we discard the 'times: not found' message from the shell.
+at_times_p=false
+(times) >/dev/null 2>&1 && at_times_p=:
+
+# CLI Arguments to pass to the debugging scripts.
+at_debug_args=
+# -e sets to true
+at_errexit_p=false
+# Shall we be verbose? ':' means no, empty means yes.
+at_verbose=:
+at_quiet=
+# Running several jobs in parallel, 0 means as many as test groups.
+at_jobs=1
+at_traceon=:
+at_trace_echo=:
+at_check_filter_trace=:
+
+# Shall we keep the debug scripts? Must be `:' when the suite is
+# run by a debug script, so that the script doesn't remove itself.
+at_debug_p=false
+# Display help message?
+at_help_p=false
+# Display the version message?
+at_version_p=false
+# List test groups?
+at_list_p=false
+# --clean
+at_clean=false
+# Test groups to run
+at_groups=
+# Whether to rerun failed tests.
+at_recheck=
+# Whether a write failure occurred
+at_write_fail=0
+
+# The directory we run the suite in. Default to . if no -C option.
+at_dir=`pwd`
+# An absolute reference to this testsuite script.
+case $as_myself in
+ [\\/]* | ?:[\\/]* ) at_myself=$as_myself ;;
+ * ) at_myself=$at_dir/$as_myself ;;
+esac
+# Whether -C is in effect.
+at_change_dir=false
+
+# Whether to enable colored test results.
+at_color=auto
+# As many question marks as there are digits in the last test group number.
+# Used to normalize the test group numbers so that `ls' lists them in
+# numerical order.
+at_format='??'
+# Description of all the test groups.
+at_help_all="1;deb-format.at:1;dpkg-deb options;dpkg-deb command-line;
+2;deb-format.at:10;dpkg-deb .deb format 0.93x;dpkg-deb deb-old;
+3;deb-format.at:168;dpkg-deb .deb format 2.x;dpkg-deb deb;
+4;deb-content.at:1;dpkg-deb .deb conffiles;dpkg-deb deb conffiles;
+5;deb-fields.at:1;dpkg-deb .deb fields;dpkg-deb deb fields;
+6;deb-split.at:1;dpkg-split options;dpkg-split command-line;
+7;deb-split.at:9;dpkg-split .deb format;dpkg-split deb-split;
+8;realpath.at:1;dpkg-realpath options;dpkg-realpath command-line;
+9;realpath.at:9;dpkg-realpath path resolving;dpkg-realpath canonicalize;
+10;divert.at:1;dpkg-divert options;dpkg-divert command-line;
+11;divert.at:83;dpkg-divert query (empty db);dpkg-divert query;
+12;divert.at:94;dpkg-divert query (list);dpkg-divert query;
+13;divert.at:134;dpkg-divert query (listpackage + truename);dpkg-divert query;
+14;divert.at:160;dpkg-divert add (local rename);dpkg-divert add;
+15;divert.at:178;dpkg-divert add (local no-rename);dpkg-divert add;
+16;divert.at:196;dpkg-divert add (rename quiet);dpkg-divert add;
+17;divert.at:213;dpkg-divert add (test rename quiet);dpkg-divert add;
+18;divert.at:226;dpkg-divert add (rename missing quiet);dpkg-divert add;
+19;divert.at:243;dpkg-divert add (local rename quiet);dpkg-divert add;
+20;divert.at:260;dpkg-divert add (package rename quiet);dpkg-divert add;
+21;divert.at:274;dpkg-divert add (rename self-link);dpkg-divert add;
+22;divert.at:292;dpkg-divert add (rename other-file);dpkg-divert add;
+23;divert.at:305;dpkg-divert add (rename missing dir);dpkg-divert add;
+24;divert.at:319;dpkg-divert add (rename read-only dir);dpkg-divert fsys;
+25;divert.at:343;dpkg-divert add (rename no-access dir);dpkg-divert fsys;
+26;divert.at:367;dpkg-divert add second diversion;dpkg-divert add;
+27;divert.at:401;dpkg-divert add third diversion;dpkg-divert add;
+28;divert.at:420;dpkg-divert add (file owned by --package);dpkg-divert add;
+29;divert.at:447;dpkg-divert remove (missing);dpkg-divert remove;
+30;divert.at:459;dpkg-divert remove (divert-to);dpkg-divert remove;
+31;divert.at:494;dpkg-divert remove (plain);dpkg-divert remove;
+32;divert.at:517;dpkg-divert remove (by-package);dpkg-divert remove;
+33;divert.at:539;dpkg-divert remove (test);dpkg-divert remove;
+34;divert.at:564;dpkg-divert db (no-access);dpkg-divert db;
+35;divert.at:580;dpkg-divert db (truncated);dpkg-divert db;
+36;divert.at:598;dpkg-divert db (read-only dir);dpkg-divert db;
+37;divert.at:613;dpkg-divert db (disk full);dpkg-divert db;
+38;divert.at:628;dpkg-divert db (pathname is dir);dpkg-divert db;
+39;chdir.at:5;dpkg chdir opts;dpkg command-line chdir;
+40;chdir.at:5;dpkg chdir env;dpkg command-line chdir;
+41;chdir.at:5;dpkg chdir env+opt admindir;dpkg command-line chdir;
+42;chdir.at:5;dpkg chdir env+opt root;dpkg command-line chdir;
+43;chdir.at:5;dpkg chdir env+opt root+admindir;dpkg command-line chdir;
+44;chdir.at:5;dpkg-divert chdir opts;dpkg-divert command-line chdir;
+45;chdir.at:5;dpkg-divert chdir env;dpkg-divert command-line chdir;
+46;chdir.at:5;dpkg-divert chdir env+opt admindir;dpkg-divert command-line chdir;
+47;chdir.at:5;dpkg-divert chdir env+opt root;dpkg-divert command-line chdir;
+48;chdir.at:5;dpkg-divert chdir env+opt root+admindir;dpkg-divert command-line chdir;
+49;chdir.at:5;dpkg-statoverride chdir opts;dpkg-statoverride command-line chdir;
+50;chdir.at:5;dpkg-statoverride chdir env;dpkg-statoverride command-line chdir;
+51;chdir.at:5;dpkg-statoverride chdir env+opt admindir;dpkg-statoverride command-line chdir;
+52;chdir.at:5;dpkg-statoverride chdir env+opt root;dpkg-statoverride command-line chdir;
+53;chdir.at:5;dpkg-statoverride chdir env+opt root+admindir;dpkg-statoverride command-line chdir;
+54;chdir.at:329;dpkg-split chdir opts;dpkg-split command-line chdir;
+55;chdir.at:329;dpkg-split chdir env;dpkg-split command-line chdir;
+56;chdir.at:329;dpkg-split chdir env+opt admindir;dpkg-split command-line chdir;
+57;chdir.at:329;dpkg-split chdir env+opt root;dpkg-split command-line chdir;
+58;chdir.at:329;dpkg-split chdir env+opt root+admindir;dpkg-split command-line chdir;
+59;chdir.at:329;dpkg-query chdir opts;dpkg-query command-line chdir;
+60;chdir.at:329;dpkg-query chdir env;dpkg-query command-line chdir;
+61;chdir.at:329;dpkg-query chdir env+opt admindir;dpkg-query command-line chdir;
+62;chdir.at:329;dpkg-query chdir env+opt root;dpkg-query command-line chdir;
+63;chdir.at:329;dpkg-query chdir env+opt root+admindir;dpkg-query command-line chdir;
+64;chdir.at:329;dpkg-trigger chdir opts;dpkg-trigger command-line chdir;
+65;chdir.at:329;dpkg-trigger chdir env;dpkg-trigger command-line chdir;
+66;chdir.at:329;dpkg-trigger chdir env+opt admindir;dpkg-trigger command-line chdir;
+67;chdir.at:329;dpkg-trigger chdir env+opt root;dpkg-trigger command-line chdir;
+68;chdir.at:329;dpkg-trigger chdir env+opt root+admindir;dpkg-trigger command-line chdir;
+"
+# List of the all the test groups.
+at_groups_all=`printf "%s\n" "$at_help_all" | sed 's/;.*//'`
+
+# at_fn_validate_ranges NAME...
+# -----------------------------
+# Validate and normalize the test group number contained in each variable
+# NAME. Leading zeroes are treated as decimal.
+at_fn_validate_ranges ()
+{
+ for at_grp
+ do
+ eval at_value=\$$at_grp
+ if test $at_value -lt 1 || test $at_value -gt 68; then
+ printf "%s\n" "invalid test group: $at_value" >&2
+ exit 1
+ fi
+ case $at_value in
+ 0*) # We want to treat leading 0 as decimal, like expr and test, but
+ # AS_VAR_ARITH treats it as octal if it uses $(( )).
+ # With XSI shells, ${at_value#${at_value%%[1-9]*}} avoids the
+ # expr fork, but it is not worth the effort to determine if the
+ # shell supports XSI when the user can just avoid leading 0.
+ eval $at_grp='`expr $at_value + 0`' ;;
+ esac
+ done
+}
+# List of the tested programs.
+at_tested='"dpkg-deb"
+"dpkg-split"
+"dpkg-realpath"
+"dpkg-divert"
+"dpkg"'
+
+
+at_prev=
+for at_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$at_prev"; then
+ at_option=$at_prev=$at_option
+ at_prev=
+ fi
+
+ case $at_option in
+ *=?*) at_optarg=`expr "X$at_option" : '[^=]*=\(.*\)'` ;;
+ *) at_optarg= ;;
+ esac
+
+ case $at_option in
+ --help | -h )
+ at_help_p=:
+ ;;
+
+ --list | -l )
+ at_list_p=:
+ ;;
+
+ --version | -V )
+ at_version_p=:
+ ;;
+
+ --clean | -c )
+ at_clean=:
+ ;;
+
+ --color )
+ at_color=always
+ ;;
+ --color=* )
+ case $at_optarg in
+ no | never | none) at_color=never ;;
+ auto | tty | if-tty) at_color=auto ;;
+ always | yes | force) at_color=always ;;
+ *) at_optname=`echo " $at_option" | sed 's/^ //; s/=.*//'`
+ as_fn_error $? "unrecognized argument to $at_optname: $at_optarg" ;;
+ esac
+ ;;
+
+ --debug | -d )
+ at_debug_p=:
+ ;;
+
+ --errexit | -e )
+ at_debug_p=:
+ at_errexit_p=:
+ ;;
+
+ --verbose | -v )
+ at_verbose=; at_quiet=:
+ ;;
+
+ --trace | -x )
+ at_traceon='set -x'
+ at_trace_echo=echo
+ at_check_filter_trace=at_fn_filter_trace
+ ;;
+
+ [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9])
+ at_fn_validate_ranges at_option
+ as_fn_append at_groups "$at_option$as_nl"
+ ;;
+
+ # Ranges
+ [0-9]- | [0-9][0-9]- | [0-9][0-9][0-9]- | [0-9][0-9][0-9][0-9]-)
+ at_range_start=`echo $at_option |tr -d X-`
+ at_fn_validate_ranges at_range_start
+ at_range=`printf "%s\n" "$at_groups_all" | \
+ sed -ne '/^'$at_range_start'$/,$p'`
+ as_fn_append at_groups "$at_range$as_nl"
+ ;;
+
+ -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | -[0-9][0-9][0-9][0-9])
+ at_range_end=`echo $at_option |tr -d X-`
+ at_fn_validate_ranges at_range_end
+ at_range=`printf "%s\n" "$at_groups_all" | \
+ sed -ne '1,/^'$at_range_end'$/p'`
+ as_fn_append at_groups "$at_range$as_nl"
+ ;;
+
+ [0-9]-[0-9] | [0-9]-[0-9][0-9] | [0-9]-[0-9][0-9][0-9] | \
+ [0-9]-[0-9][0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9] | \
+ [0-9][0-9]-[0-9][0-9][0-9] | [0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+ [0-9][0-9][0-9]-[0-9][0-9][0-9] | \
+ [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] | \
+ [0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9] )
+ at_range_start=`expr $at_option : '\(.*\)-'`
+ at_range_end=`expr $at_option : '.*-\(.*\)'`
+ if test $at_range_start -gt $at_range_end; then
+ at_tmp=$at_range_end
+ at_range_end=$at_range_start
+ at_range_start=$at_tmp
+ fi
+ at_fn_validate_ranges at_range_start at_range_end
+ at_range=`printf "%s\n" "$at_groups_all" | \
+ sed -ne '/^'$at_range_start'$/,/^'$at_range_end'$/p'`
+ as_fn_append at_groups "$at_range$as_nl"
+ ;;
+
+ # Directory selection.
+ --directory | -C )
+ at_prev=--directory
+ ;;
+ --directory=* )
+ at_change_dir=:
+ at_dir=$at_optarg
+ if test x- = "x$at_dir" ; then
+ at_dir=./-
+ fi
+ ;;
+
+ # Parallel execution.
+ --jobs | -j )
+ at_jobs=0
+ ;;
+ --jobs=* | -j[0-9]* )
+ if test -n "$at_optarg"; then
+ at_jobs=$at_optarg
+ else
+ at_jobs=`expr X$at_option : 'X-j\(.*\)'`
+ fi
+ case $at_jobs in *[!0-9]*)
+ at_optname=`echo " $at_option" | sed 's/^ //; s/[0-9=].*//'`
+ as_fn_error $? "non-numeric argument to $at_optname: $at_jobs" ;;
+ esac
+ ;;
+
+ # Keywords.
+ --keywords | -k )
+ at_prev=--keywords
+ ;;
+ --keywords=* )
+ at_groups_selected=$at_help_all
+ at_save_IFS=$IFS
+ IFS=,
+ set X $at_optarg
+ shift
+ IFS=$at_save_IFS
+ for at_keyword
+ do
+ at_invert=
+ case $at_keyword in
+ '!'*)
+ at_invert="-v"
+ at_keyword=`expr "X$at_keyword" : 'X!\(.*\)'`
+ ;;
+ esac
+ # It is on purpose that we match the test group titles too.
+ at_groups_selected=`printf "%s\n" "$at_groups_selected" |
+ grep -i $at_invert "^[1-9][^;]*;.*[; ]$at_keyword[ ;]"`
+ done
+ # Smash the keywords.
+ at_groups_selected=`printf "%s\n" "$at_groups_selected" | sed 's/;.*//'`
+ as_fn_append at_groups "$at_groups_selected$as_nl"
+ ;;
+ --recheck)
+ at_recheck=:
+ ;;
+
+ *=*)
+ at_envvar=`expr "x$at_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $at_envvar in
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$at_envvar'" ;;
+ esac
+ at_value=`printf "%s\n" "$at_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ # Export now, but save eval for later and for debug scripts.
+ export $at_envvar
+ as_fn_append at_debug_args " $at_envvar='$at_value'"
+ ;;
+
+ *) printf "%s\n" "$as_me: invalid option: $at_option" >&2
+ printf "%s\n" "Try \`$0 --help' for more information." >&2
+ exit 1
+ ;;
+ esac
+done
+
+# Verify our last option didn't require an argument
+if test -n "$at_prev"
+then :
+ as_fn_error $? "\`$at_prev' requires an argument"
+fi
+
+# The file containing the suite.
+at_suite_log=$at_dir/$as_me.log
+
+# Selected test groups.
+if test -z "$at_groups$at_recheck"; then
+ at_groups=$at_groups_all
+else
+ if test -n "$at_recheck" && test -r "$at_suite_log"; then
+ at_oldfails=`sed -n '
+ /^Failed tests:$/,/^Skipped tests:$/{
+ s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+ }
+ /^Unexpected passes:$/,/^## Detailed failed tests/{
+ s/^[ ]*\([1-9][0-9]*\):.*/\1/p
+ }
+ /^## Detailed failed tests/q
+ ' "$at_suite_log"`
+ as_fn_append at_groups "$at_oldfails$as_nl"
+ fi
+ # Sort the tests, removing duplicates.
+ at_groups=`printf "%s\n" "$at_groups" | sort -nu | sed '/^$/d'`
+fi
+
+if test x"$at_color" = xalways \
+ || { test x"$at_color" = xauto && test -t 1; }; then
+ at_red=`printf '\033[0;31m'`
+ at_grn=`printf '\033[0;32m'`
+ at_lgn=`printf '\033[1;32m'`
+ at_blu=`printf '\033[1;34m'`
+ at_std=`printf '\033[m'`
+else
+ at_red= at_grn= at_lgn= at_blu= at_std=
+fi
+
+# Help message.
+if $at_help_p; then
+ cat <<_ATEOF || at_write_fail=1
+Usage: $0 [OPTION]... [VARIABLE=VALUE]... [TESTS]
+
+Run all the tests, or the selected TESTS, given by numeric ranges, and
+save a detailed log file. Upon failure, create debugging scripts.
+
+Do not change environment variables directly. Instead, set them via
+command line arguments. Set \`AUTOTEST_PATH' to select the executables
+to exercise. Each relative directory is expanded as build and source
+directories relative to the top level of this distribution.
+E.g., from within the build directory /tmp/foo-1.0, invoking this:
+
+ $ $0 AUTOTEST_PATH=bin
+
+is equivalent to the following, assuming the source directory is /src/foo-1.0:
+
+ PATH=/tmp/foo-1.0/bin:/src/foo-1.0/bin:\$PATH $0
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Operation modes:
+ -h, --help print the help message, then exit
+ -V, --version print version number, then exit
+ -c, --clean remove all the files this test suite might create and exit
+ -l, --list describes all the tests, or the selected TESTS
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Execution tuning:
+ -C, --directory=DIR
+ change to directory DIR before starting
+ --color[=never|auto|always]
+ disable colored test results, or enable even without terminal
+ -j, --jobs[=N]
+ Allow N jobs at once; infinite jobs with no arg (default 1)
+ -k, --keywords=KEYWORDS
+ select the tests matching all the comma-separated KEYWORDS
+ multiple \`-k' accumulate; prefixed \`!' negates a KEYWORD
+ --recheck select all tests that failed or passed unexpectedly last time
+ -e, --errexit abort as soon as a test fails; implies --debug
+ -v, --verbose force more detailed output
+ default for debugging scripts
+ -d, --debug inhibit clean up and top-level logging
+ default for debugging scripts
+ -x, --trace enable tests shell tracing
+_ATEOF
+cat <<_ATEOF || at_write_fail=1
+
+Report bugs to <debian-dpkg@lists.debian.org>.
+dpkg home page: <https://wiki.debian.org/Teams/Dpkg>.
+_ATEOF
+ exit $at_write_fail
+fi
+
+# List of tests.
+if $at_list_p; then
+ cat <<_ATEOF || at_write_fail=1
+dpkg 1.21.22 test suite: dpkg tools functional test suite test groups:
+
+ NUM: FILE-NAME:LINE TEST-GROUP-NAME
+ KEYWORDS
+
+_ATEOF
+ # Pass an empty line as separator between selected groups and help.
+ printf "%s\n" "$at_groups$as_nl$as_nl$at_help_all" |
+ awk 'NF == 1 && FS != ";" {
+ selected[$ 1] = 1
+ next
+ }
+ /^$/ { FS = ";" }
+ NF > 0 {
+ if (selected[$ 1]) {
+ printf " %3d: %-18s %s\n", $ 1, $ 2, $ 3
+ if ($ 4) {
+ lmax = 79
+ indent = " "
+ line = indent
+ len = length (line)
+ n = split ($ 4, a, " ")
+ for (i = 1; i <= n; i++) {
+ l = length (a[i]) + 1
+ if (i > 1 && len + l > lmax) {
+ print line
+ line = indent " " a[i]
+ len = length (line)
+ } else {
+ line = line " " a[i]
+ len += l
+ }
+ }
+ if (n)
+ print line
+ }
+ }
+ }' || at_write_fail=1
+ exit $at_write_fail
+fi
+if $at_version_p; then
+ printf "%s\n" "$as_me (dpkg 1.21.22)" &&
+ cat <<\_ATEOF || at_write_fail=1
+
+Copyright (C) 2021 Free Software Foundation, Inc.
+This test suite is free software; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+_ATEOF
+ exit $at_write_fail
+fi
+
+# Should we print banners? Yes if more than one test is run.
+case $at_groups in #(
+ *$as_nl* )
+ at_print_banners=: ;; #(
+ * ) at_print_banners=false ;;
+esac
+# Text for banner N, set to a single space once printed.
+# Banner 1. testsuite.at:5
+# Category starts at test group 1.
+at_banner_text_1="Binary .deb packages"
+# Banner 2. testsuite.at:11
+# Category starts at test group 6.
+at_banner_text_2="Split .deb packages"
+# Banner 3. testsuite.at:15
+# Category starts at test group 8.
+at_banner_text_3="Resolve pathnames"
+# Banner 4. testsuite.at:19
+# Category starts at test group 10.
+at_banner_text_4="Diversions"
+# Banner 5. testsuite.at:23
+# Category starts at test group 39.
+at_banner_text_5="Change directory options"
+
+# Take any -C into account.
+if $at_change_dir ; then
+ test x != "x$at_dir" && cd "$at_dir" \
+ || as_fn_error $? "unable to change directory"
+ at_dir=`pwd`
+fi
+
+# Load the config files for any default variable assignments.
+for at_file in atconfig atlocal
+do
+ test -r $at_file || continue
+ . ./$at_file || as_fn_error $? "invalid content: $at_file"
+done
+
+# Autoconf <=2.59b set at_top_builddir instead of at_top_build_prefix:
+: "${at_top_build_prefix=$at_top_builddir}"
+
+# Perform any assignments requested during argument parsing.
+eval "$at_debug_args"
+
+# atconfig delivers names relative to the directory the test suite is
+# in, but the groups themselves are run in testsuite-dir/group-dir.
+if test -n "$at_top_srcdir"; then
+ builddir=../..
+ for at_dir_var in srcdir top_srcdir top_build_prefix
+ do
+ eval at_val=\$at_$at_dir_var
+ case $at_val in
+ [\\/$]* | ?:[\\/]* ) at_prefix= ;;
+ *) at_prefix=../../ ;;
+ esac
+ eval "$at_dir_var=\$at_prefix\$at_val"
+ done
+fi
+
+## -------------------- ##
+## Directory structure. ##
+## -------------------- ##
+
+# This is the set of directories and files used by this script
+# (non-literals are capitalized):
+#
+# TESTSUITE - the testsuite
+# TESTSUITE.log - summarizes the complete testsuite run
+# TESTSUITE.dir/ - created during a run, remains after -d or failed test
+# + at-groups/ - during a run: status of all groups in run
+# | + NNN/ - during a run: meta-data about test group NNN
+# | | + check-line - location (source file and line) of current AT_CHECK
+# | | + status - exit status of current AT_CHECK
+# | | + stdout - stdout of current AT_CHECK
+# | | + stder1 - stderr, including trace
+# | | + stderr - stderr, with trace filtered out
+# | | + test-source - portion of testsuite that defines group
+# | | + times - timestamps for computing duration
+# | | + pass - created if group passed
+# | | + xpass - created if group xpassed
+# | | + fail - created if group failed
+# | | + xfail - created if group xfailed
+# | | + skip - created if group skipped
+# + at-stop - during a run: end the run if this file exists
+# + at-source-lines - during a run: cache of TESTSUITE line numbers for extraction
+# + 0..NNN/ - created for each group NNN, remains after -d or failed test
+# | + TESTSUITE.log - summarizes the group results
+# | + ... - files created during the group
+
+# The directory the whole suite works in.
+# Should be absolute to let the user `cd' at will.
+at_suite_dir=$at_dir/$as_me.dir
+# The file containing the suite ($at_dir might have changed since earlier).
+at_suite_log=$at_dir/$as_me.log
+# The directory containing helper files per test group.
+at_helper_dir=$at_suite_dir/at-groups
+# Stop file: if it exists, do not start new jobs.
+at_stop_file=$at_suite_dir/at-stop
+# The fifo used for the job dispatcher.
+at_job_fifo=$at_suite_dir/at-job-fifo
+
+if $at_clean; then
+ test -d "$at_suite_dir" &&
+ find "$at_suite_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+ rm -f -r "$at_suite_dir" "$at_suite_log"
+ exit $?
+fi
+
+# Don't take risks: use only absolute directories in PATH.
+#
+# For stand-alone test suites (ie. atconfig was not found),
+# AUTOTEST_PATH is relative to `.'.
+#
+# For embedded test suites, AUTOTEST_PATH is relative to the top level
+# of the package. Then expand it into build/src parts, since users
+# may create executables in both places.
+AUTOTEST_PATH=`printf "%s\n" "$AUTOTEST_PATH" | sed "s|:|$PATH_SEPARATOR|g"`
+at_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $AUTOTEST_PATH $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -n "$at_path" && as_fn_append at_path $PATH_SEPARATOR
+case $as_dir in
+ [\\/]* | ?:[\\/]* )
+ as_fn_append at_path "$as_dir"
+ ;;
+ * )
+ if test -z "$at_top_build_prefix"; then
+ # Stand-alone test suite.
+ as_fn_append at_path "$as_dir"
+ else
+ # Embedded test suite.
+ as_fn_append at_path "$at_top_build_prefix$as_dir$PATH_SEPARATOR"
+ as_fn_append at_path "$at_top_srcdir/$as_dir"
+ fi
+ ;;
+esac
+ done
+IFS=$as_save_IFS
+
+
+# Now build and simplify PATH.
+#
+# There might be directories that don't exist, but don't redirect
+# builtins' (eg., cd) stderr directly: Ultrix's sh hates that.
+at_new_path=
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $at_path
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -d "$as_dir" || continue
+case $as_dir in
+ [\\/]* | ?:[\\/]* ) ;;
+ * ) as_dir=`(cd "$as_dir" && pwd) 2>/dev/null` ;;
+esac
+case $PATH_SEPARATOR$at_new_path$PATH_SEPARATOR in
+ *$PATH_SEPARATOR$as_dir$PATH_SEPARATOR*) ;;
+ $PATH_SEPARATOR$PATH_SEPARATOR) at_new_path=$as_dir ;;
+ *) as_fn_append at_new_path "$PATH_SEPARATOR$as_dir" ;;
+esac
+ done
+IFS=$as_save_IFS
+
+PATH=$at_new_path
+export PATH
+
+# Setting up the FDs.
+
+
+
+# 5 is the log file. Not to be overwritten if `-d'.
+if $at_debug_p; then
+ at_suite_log=/dev/null
+else
+ : >"$at_suite_log"
+fi
+exec 5>>"$at_suite_log"
+
+# Banners and logs.
+printf "%s\n" "## ---------------------------------------------------------- ##
+## dpkg 1.21.22 test suite: dpkg tools functional test suite. ##
+## ---------------------------------------------------------- ##"
+{
+ printf "%s\n" "## ---------------------------------------------------------- ##
+## dpkg 1.21.22 test suite: dpkg tools functional test suite. ##
+## ---------------------------------------------------------- ##"
+ echo
+
+ printf "%s\n" "$as_me: command line was:"
+ printf "%s\n" " \$ $0 $at_cli_args"
+ echo
+
+ # If ChangeLog exists, list a few lines in case it might help determining
+ # the exact version.
+ if test -n "$at_top_srcdir" && test -f "$at_top_srcdir/ChangeLog"; then
+ printf "%s\n" "## ---------- ##
+## ChangeLog. ##
+## ---------- ##"
+ echo
+ sed 's/^/| /;10q' "$at_top_srcdir/ChangeLog"
+ echo
+ fi
+
+ {
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ printf "%s\n" "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+}
+ echo
+
+ # Contents of the config files.
+ for at_file in atconfig atlocal
+ do
+ test -r $at_file || continue
+ printf "%s\n" "$as_me: $at_file:"
+ sed 's/^/| /' $at_file
+ echo
+ done
+} >&5
+
+
+## ------------------------- ##
+## Autotest shell functions. ##
+## ------------------------- ##
+
+# at_fn_banner NUMBER
+# -------------------
+# Output banner NUMBER, provided the testsuite is running multiple groups and
+# this particular banner has not yet been printed.
+at_fn_banner ()
+{
+ $at_print_banners || return 0
+ eval at_banner_text=\$at_banner_text_$1
+ test "x$at_banner_text" = "x " && return 0
+ eval "at_banner_text_$1=\" \""
+ if test -z "$at_banner_text"; then
+ $at_first || echo
+ else
+ printf "%s\n" "$as_nl$at_banner_text$as_nl"
+ fi
+} # at_fn_banner
+
+# at_fn_check_prepare_notrace REASON LINE
+# ---------------------------------------
+# Perform AT_CHECK preparations for the command at LINE for an untraceable
+# command; REASON is the reason for disabling tracing.
+at_fn_check_prepare_notrace ()
+{
+ $at_trace_echo "Not enabling shell tracing (command contains $1)"
+ printf "%s\n" "$2" >"$at_check_line_file"
+ at_check_trace=: at_check_filter=:
+ : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_trace LINE
+# ------------------------------
+# Perform AT_CHECK preparations for the command at LINE for a traceable
+# command.
+at_fn_check_prepare_trace ()
+{
+ printf "%s\n" "$1" >"$at_check_line_file"
+ at_check_trace=$at_traceon at_check_filter=$at_check_filter_trace
+ : >"$at_stdout"; : >"$at_stderr"
+}
+
+# at_fn_check_prepare_dynamic COMMAND LINE
+# ----------------------------------------
+# Decide if COMMAND at LINE is traceable at runtime, and call the appropriate
+# preparation function.
+at_fn_check_prepare_dynamic ()
+{
+ case $1 in
+ *$as_nl*)
+ at_fn_check_prepare_notrace 'an embedded newline' "$2" ;;
+ *)
+ at_fn_check_prepare_trace "$2" ;;
+ esac
+}
+
+# at_fn_filter_trace
+# ------------------
+# Remove the lines in the file "$at_stderr" generated by "set -x" and print
+# them to stderr.
+at_fn_filter_trace ()
+{
+ mv "$at_stderr" "$at_stder1"
+ grep '^ *+' "$at_stder1" >&2
+ grep -v '^ *+' "$at_stder1" >"$at_stderr"
+}
+
+# at_fn_log_failure FILE-LIST
+# ---------------------------
+# Copy the files in the list on stdout with a "> " prefix, and exit the shell
+# with a failure exit code.
+at_fn_log_failure ()
+{
+ for file
+ do printf "%s\n" "$file:"; sed 's/^/> /' "$file"; done
+ echo 1 > "$at_status_file"
+ exit 1
+}
+
+# at_fn_check_skip EXIT-CODE LINE
+# -------------------------------
+# Check whether EXIT-CODE is a special exit code (77 or 99), and if so exit
+# the test group subshell with that same exit code. Use LINE in any report
+# about test failure.
+at_fn_check_skip ()
+{
+ case $1 in
+ 99) echo 99 > "$at_status_file"; at_failed=:
+ printf "%s\n" "$2: hard failure"; exit 99;;
+ 77) echo 77 > "$at_status_file"; exit 77;;
+ esac
+}
+
+# at_fn_check_status EXPECTED EXIT-CODE LINE
+# ------------------------------------------
+# Check whether EXIT-CODE is the EXPECTED exit code, and if so do nothing.
+# Otherwise, if it is 77 or 99, exit the test group subshell with that same
+# exit code; if it is anything else print an error message referring to LINE,
+# and fail the test.
+at_fn_check_status ()
+{
+ case $2 in
+ $1 ) ;;
+ 77) echo 77 > "$at_status_file"; exit 77;;
+ 99) echo 99 > "$at_status_file"; at_failed=:
+ printf "%s\n" "$3: hard failure"; exit 99;;
+ *) printf "%s\n" "$3: exit code was $2, expected $1"
+ at_failed=:;;
+ esac
+}
+
+# at_fn_diff_devnull FILE
+# -----------------------
+# Emit a diff between /dev/null and FILE. Uses "test -s" to avoid useless diff
+# invocations.
+at_fn_diff_devnull ()
+{
+ test -s "$1" || return 0
+ $at_diff "$at_devnull" "$1"
+}
+
+# at_fn_test NUMBER
+# -----------------
+# Parse out test NUMBER from the tail of this file.
+at_fn_test ()
+{
+ eval at_sed=\$at_sed$1
+ sed "$at_sed" "$at_myself" > "$at_test_source"
+}
+
+# at_fn_create_debugging_script
+# -----------------------------
+# Create the debugging script $at_group_dir/run which will reproduce the
+# current test group.
+at_fn_create_debugging_script ()
+{
+ {
+ echo "#! /bin/sh" &&
+ echo 'test ${ZSH_VERSION+y} && alias -g '\''${1+"$@"}'\''='\''"$@"'\''' &&
+ printf "%s\n" "cd '$at_dir'" &&
+ printf "%s\n" "exec \${CONFIG_SHELL-$SHELL} \"$at_myself\" -v -d $at_debug_args $at_group \${1+\"\$@\"}" &&
+ echo 'exit 1'
+ } >"$at_group_dir/run" &&
+ chmod +x "$at_group_dir/run"
+}
+
+## -------------------------------- ##
+## End of autotest shell functions. ##
+## -------------------------------- ##
+{
+ printf "%s\n" "## ---------------- ##
+## Tested programs. ##
+## ---------------- ##"
+ echo
+} >&5
+
+# Report what programs are being tested.
+for at_program in : `eval echo $at_tested`
+do
+ case $at_program in #(
+ :) :
+ continue ;; #(
+ [\\/]* | ?:[\\/]*) :
+ at_program_=$at_program ;; #(
+ *) :
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -f "$as_dir$at_program" && break
+ done
+IFS=$as_save_IFS
+
+ at_program_=$as_dir$at_program ;;
+esac
+
+ if test -f "$at_program_"; then
+ {
+ printf "%s\n" "$at_srcdir/testsuite.at:1: $at_program_ --version"
+ "$at_program_" --version </dev/null
+ echo
+ } >&5 2>&1
+ else
+ as_fn_error $? "cannot find $at_program" "$LINENO" 5
+ fi
+done
+
+{
+ printf "%s\n" "## ------------------ ##
+## Running the tests. ##
+## ------------------ ##"
+} >&5
+
+at_start_date=`date`
+at_start_time=`date +%s 2>/dev/null`
+printf "%s\n" "$as_me: starting at: $at_start_date" >&5
+
+# Create the master directory if it doesn't already exist.
+as_dir="$at_suite_dir"; as_fn_mkdir_p ||
+ as_fn_error $? "cannot create \`$at_suite_dir'" "$LINENO" 5
+
+# Can we diff with `/dev/null'? DU 5.0 refuses.
+if diff /dev/null /dev/null >/dev/null 2>&1; then
+ at_devnull=/dev/null
+else
+ at_devnull=$at_suite_dir/devnull
+ >"$at_devnull"
+fi
+
+# Use `diff -u' when possible.
+if at_diff=`diff -u "$at_devnull" "$at_devnull" 2>&1` && test -z "$at_diff"
+then
+ at_diff='diff -u'
+else
+ at_diff=diff
+fi
+
+# Get the last needed group.
+for at_group in : $at_groups; do :; done
+
+# Extract the start and end lines of each test group at the tail
+# of this file
+awk '
+BEGIN { FS="" }
+/^#AT_START_/ {
+ start = NR
+}
+/^#AT_STOP_/ {
+ test = substr ($ 0, 10)
+ print "at_sed" test "=\"1," start "d;" (NR-1) "q\""
+ if (test == "'"$at_group"'") exit
+}' "$at_myself" > "$at_suite_dir/at-source-lines" &&
+. "$at_suite_dir/at-source-lines" ||
+ as_fn_error $? "cannot create test line number cache" "$LINENO" 5
+rm -f "$at_suite_dir/at-source-lines"
+
+# Set number of jobs for `-j'; avoid more jobs than test groups.
+set X $at_groups; shift; at_max_jobs=$#
+if test $at_max_jobs -eq 0; then
+ at_jobs=1
+fi
+if test $at_jobs -ne 1 &&
+ { test $at_jobs -eq 0 || test $at_jobs -gt $at_max_jobs; }; then
+ at_jobs=$at_max_jobs
+fi
+
+# If parallel mode, don't output banners, don't split summary lines.
+if test $at_jobs -ne 1; then
+ at_print_banners=false
+ at_quiet=:
+fi
+
+# Set up helper dirs.
+rm -rf "$at_helper_dir" &&
+mkdir "$at_helper_dir" &&
+cd "$at_helper_dir" &&
+{ test -z "$at_groups" || mkdir $at_groups; } ||
+as_fn_error $? "testsuite directory setup failed" "$LINENO" 5
+
+# Functions for running a test group. We leave the actual
+# test group execution outside of a shell function in order
+# to avoid hitting zsh 4.x exit status bugs.
+
+# at_fn_group_prepare
+# -------------------
+# Prepare for running a test group.
+at_fn_group_prepare ()
+{
+ # The directory for additional per-group helper files.
+ at_job_dir=$at_helper_dir/$at_group
+ # The file containing the location of the last AT_CHECK.
+ at_check_line_file=$at_job_dir/check-line
+ # The file containing the exit status of the last command.
+ at_status_file=$at_job_dir/status
+ # The files containing the output of the tested commands.
+ at_stdout=$at_job_dir/stdout
+ at_stder1=$at_job_dir/stder1
+ at_stderr=$at_job_dir/stderr
+ # The file containing the code for a test group.
+ at_test_source=$at_job_dir/test-source
+ # The file containing dates.
+ at_times_file=$at_job_dir/times
+
+ # Be sure to come back to the top test directory.
+ cd "$at_suite_dir"
+
+ # Clearly separate the test groups when verbose.
+ $at_first || $at_verbose echo
+
+ at_group_normalized=$at_group
+
+ eval 'while :; do
+ case $at_group_normalized in #(
+ '"$at_format"'*) break;;
+ esac
+ at_group_normalized=0$at_group_normalized
+ done'
+
+
+ # Create a fresh directory for the next test group, and enter.
+ # If one already exists, the user may have invoked ./run from
+ # within that directory; we remove the contents, but not the
+ # directory itself, so that we aren't pulling the rug out from
+ # under the shell's notion of the current directory.
+ at_group_dir=$at_suite_dir/$at_group_normalized
+ at_group_log=$at_group_dir/$as_me.log
+ if test -d "$at_group_dir"
+then
+ find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx {} \;
+ rm -fr "$at_group_dir"/* "$at_group_dir"/.[!.] "$at_group_dir"/.??*
+fi ||
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: test directory for $at_group_normalized could not be cleaned" >&5
+printf "%s\n" "$as_me: WARNING: test directory for $at_group_normalized could not be cleaned" >&2;}
+ # Be tolerant if the above `rm' was not able to remove the directory.
+ as_dir="$at_group_dir"; as_fn_mkdir_p
+
+ echo 0 > "$at_status_file"
+
+ # In verbose mode, append to the log file *and* show on
+ # the standard output; in quiet mode only write to the log.
+ if test -z "$at_verbose"; then
+ at_tee_pipe='tee -a "$at_group_log"'
+ else
+ at_tee_pipe='cat >> "$at_group_log"'
+ fi
+}
+
+# at_fn_group_banner ORDINAL LINE DESC PAD [BANNER]
+# -------------------------------------------------
+# Declare the test group ORDINAL, located at LINE with group description DESC,
+# and residing under BANNER. Use PAD to align the status column.
+at_fn_group_banner ()
+{
+ at_setup_line="$2"
+ test -n "$5" && at_fn_banner $5
+ at_desc="$3"
+ case $1 in
+ [0-9]) at_desc_line=" $1: ";;
+ [0-9][0-9]) at_desc_line=" $1: " ;;
+ *) at_desc_line="$1: " ;;
+ esac
+ as_fn_append at_desc_line "$3$4"
+ $at_quiet printf %s "$at_desc_line"
+ echo "# -*- compilation -*-" >> "$at_group_log"
+}
+
+# at_fn_group_postprocess
+# -----------------------
+# Perform cleanup after running a test group.
+at_fn_group_postprocess ()
+{
+ # Be sure to come back to the suite directory, in particular
+ # since below we might `rm' the group directory we are in currently.
+ cd "$at_suite_dir"
+
+ if test ! -f "$at_check_line_file"; then
+ sed "s/^ */$as_me: WARNING: /" <<_ATEOF
+ A failure happened in a test group before any test could be
+ run. This means that test suite is improperly designed. Please
+ report this failure to <debian-dpkg@lists.debian.org>.
+_ATEOF
+ printf "%s\n" "$at_setup_line" >"$at_check_line_file"
+ at_status=99
+ fi
+ $at_verbose printf %s "$at_group. $at_setup_line: "
+ printf %s "$at_group. $at_setup_line: " >> "$at_group_log"
+ case $at_xfail:$at_status in
+ yes:0)
+ at_msg="UNEXPECTED PASS"
+ at_res=xpass
+ at_errexit=$at_errexit_p
+ at_color=$at_red
+ ;;
+ no:0)
+ at_msg="ok"
+ at_res=pass
+ at_errexit=false
+ at_color=$at_grn
+ ;;
+ *:77)
+ at_msg='skipped ('`cat "$at_check_line_file"`')'
+ at_res=skip
+ at_errexit=false
+ at_color=$at_blu
+ ;;
+ no:* | *:99)
+ at_msg='FAILED ('`cat "$at_check_line_file"`')'
+ at_res=fail
+ at_errexit=$at_errexit_p
+ at_color=$at_red
+ ;;
+ yes:*)
+ at_msg='expected failure ('`cat "$at_check_line_file"`')'
+ at_res=xfail
+ at_errexit=false
+ at_color=$at_lgn
+ ;;
+ esac
+ echo "$at_res" > "$at_job_dir/$at_res"
+ # In parallel mode, output the summary line only afterwards.
+ if test $at_jobs -ne 1 && test -n "$at_verbose"; then
+ printf "%s\n" "$at_desc_line $at_color$at_msg$at_std"
+ else
+ # Make sure there is a separator even with long titles.
+ printf "%s\n" " $at_color$at_msg$at_std"
+ fi
+ at_log_msg="$at_group. $at_desc ($at_setup_line): $at_msg"
+ case $at_status in
+ 0|77)
+ # $at_times_file is only available if the group succeeded.
+ # We're not including the group log, so the success message
+ # is written in the global log separately. But we also
+ # write to the group log in case they're using -d.
+ if test -f "$at_times_file"; then
+ at_log_msg="$at_log_msg ("`sed 1d "$at_times_file"`')'
+ rm -f "$at_times_file"
+ fi
+ printf "%s\n" "$at_log_msg" >> "$at_group_log"
+ printf "%s\n" "$at_log_msg" >&5
+
+ # Cleanup the group directory, unless the user wants the files
+ # or the success was unexpected.
+ if $at_debug_p || test $at_res = xpass; then
+ at_fn_create_debugging_script
+ if test $at_res = xpass && $at_errexit; then
+ echo stop > "$at_stop_file"
+ fi
+ else
+ if test -d "$at_group_dir"; then
+ find "$at_group_dir" -type d ! -perm -700 -exec chmod u+rwx \{\} \;
+ rm -fr "$at_group_dir"
+ fi
+ rm -f "$at_test_source"
+ fi
+ ;;
+ *)
+ # Upon failure, include the log into the testsuite's global
+ # log. The failure message is written in the group log. It
+ # is later included in the global log.
+ printf "%s\n" "$at_log_msg" >> "$at_group_log"
+
+ # Upon failure, keep the group directory for autopsy, and create
+ # the debugging script. With -e, do not start any further tests.
+ at_fn_create_debugging_script
+ if $at_errexit; then
+ echo stop > "$at_stop_file"
+ fi
+ ;;
+ esac
+}
+
+
+## ------------ ##
+## Driver loop. ##
+## ------------ ##
+
+
+if (set -m && set +m && set +b) >/dev/null 2>&1; then
+ set +b
+ at_job_control_on='set -m' at_job_control_off='set +m' at_job_group=-
+else
+ at_job_control_on=: at_job_control_off=: at_job_group=
+fi
+
+for at_signal in 1 2 15; do
+ trap 'set +x; set +e
+ $at_job_control_off
+ at_signal='"$at_signal"'
+ echo stop > "$at_stop_file"
+ trap "" $at_signal
+ at_pgids=
+ for at_pgid in `jobs -p 2>/dev/null`; do
+ at_pgids="$at_pgids $at_job_group$at_pgid"
+ done
+ test -z "$at_pgids" || kill -$at_signal $at_pgids 2>/dev/null
+ wait
+ if test "$at_jobs" -eq 1 || test -z "$at_verbose"; then
+ echo >&2
+ fi
+ at_signame=`kill -l $at_signal 2>&1 || echo $at_signal`
+ set x $at_signame
+ test 1 -gt 2 && at_signame=$at_signal
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: caught signal $at_signame, bailing out" >&5
+printf "%s\n" "$as_me: WARNING: caught signal $at_signame, bailing out" >&2;}
+ as_fn_arith 128 + $at_signal && exit_status=$as_val
+ as_fn_exit $exit_status' $at_signal
+done
+
+rm -f "$at_stop_file"
+at_first=:
+
+if test $at_jobs -ne 1 &&
+ rm -f "$at_job_fifo" &&
+ test -n "$at_job_group" &&
+ ( mkfifo "$at_job_fifo" && trap 'exit 1' PIPE STOP TSTP ) 2>/dev/null
+then
+ # FIFO job dispatcher.
+
+ trap 'at_pids=
+ for at_pid in `jobs -p`; do
+ at_pids="$at_pids $at_job_group$at_pid"
+ done
+ if test -n "$at_pids"; then
+ at_sig=TSTP
+ test ${TMOUT+y} && at_sig=STOP
+ kill -$at_sig $at_pids 2>/dev/null
+ fi
+ kill -STOP $$
+ test -z "$at_pids" || kill -CONT $at_pids 2>/dev/null' TSTP
+
+ echo
+ # Turn jobs into a list of numbers, starting from 1.
+ at_joblist=`printf "%s\n" "$at_groups" | sed -n 1,${at_jobs}p`
+
+ set X $at_joblist
+ shift
+ for at_group in $at_groups; do
+ $at_job_control_on 2>/dev/null
+ (
+ # Start one test group.
+ $at_job_control_off
+ if $at_first; then
+ exec 7>"$at_job_fifo"
+ else
+ exec 6<&-
+ fi
+ trap 'set +x; set +e
+ trap "" PIPE
+ echo stop > "$at_stop_file"
+ echo >&7
+ as_fn_exit 141' PIPE
+ at_fn_group_prepare
+ if cd "$at_group_dir" &&
+ at_fn_test $at_group &&
+ . "$at_test_source"
+ then :; else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+printf "%s\n" "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+ at_failed=:
+ fi
+ at_fn_group_postprocess
+ echo >&7
+ ) &
+ $at_job_control_off
+ if $at_first; then
+ at_first=false
+ exec 6<"$at_job_fifo" 7>"$at_job_fifo"
+ fi
+ shift # Consume one token.
+ if test $# -gt 0; then :; else
+ read at_token <&6 || break
+ set x $*
+ fi
+ test -f "$at_stop_file" && break
+ done
+ exec 7>&-
+ # Read back the remaining ($at_jobs - 1) tokens.
+ set X $at_joblist
+ shift
+ if test $# -gt 0; then
+ shift
+ for at_job
+ do
+ read at_token
+ done <&6
+ fi
+ exec 6<&-
+ wait
+else
+ # Run serially, avoid forks and other potential surprises.
+ for at_group in $at_groups; do
+ at_fn_group_prepare
+ if cd "$at_group_dir" &&
+ at_fn_test $at_group &&
+ . "$at_test_source"; then :; else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unable to parse test group: $at_group" >&5
+printf "%s\n" "$as_me: WARNING: unable to parse test group: $at_group" >&2;}
+ at_failed=:
+ fi
+ at_fn_group_postprocess
+ test -f "$at_stop_file" && break
+ at_first=false
+ done
+fi
+
+# Wrap up the test suite with summary statistics.
+cd "$at_helper_dir"
+
+# Use ?..???? when the list must remain sorted, the faster * otherwise.
+at_pass_list=`for f in */pass; do echo $f; done | sed '/\*/d; s,/pass,,'`
+at_skip_list=`for f in */skip; do echo $f; done | sed '/\*/d; s,/skip,,'`
+at_xfail_list=`for f in */xfail; do echo $f; done | sed '/\*/d; s,/xfail,,'`
+at_xpass_list=`for f in ?/xpass ??/xpass ???/xpass ????/xpass; do
+ echo $f; done | sed '/?/d; s,/xpass,,'`
+at_fail_list=`for f in ?/fail ??/fail ???/fail ????/fail; do
+ echo $f; done | sed '/?/d; s,/fail,,'`
+
+set X $at_pass_list $at_xpass_list $at_xfail_list $at_fail_list $at_skip_list
+shift; at_group_count=$#
+set X $at_xpass_list; shift; at_xpass_count=$#; at_xpass_list=$*
+set X $at_xfail_list; shift; at_xfail_count=$#
+set X $at_fail_list; shift; at_fail_count=$#; at_fail_list=$*
+set X $at_skip_list; shift; at_skip_count=$#
+
+as_fn_arith $at_group_count - $at_skip_count && at_run_count=$as_val
+as_fn_arith $at_xpass_count + $at_fail_count && at_unexpected_count=$as_val
+as_fn_arith $at_xfail_count + $at_fail_count && at_total_fail_count=$as_val
+
+# Back to the top directory.
+cd "$at_dir"
+rm -rf "$at_helper_dir"
+
+# Compute the duration of the suite.
+at_stop_date=`date`
+at_stop_time=`date +%s 2>/dev/null`
+printf "%s\n" "$as_me: ending at: $at_stop_date" >&5
+case $at_start_time,$at_stop_time in
+ [0-9]*,[0-9]*)
+ as_fn_arith $at_stop_time - $at_start_time && at_duration_s=$as_val
+ as_fn_arith $at_duration_s / 60 && at_duration_m=$as_val
+ as_fn_arith $at_duration_m / 60 && at_duration_h=$as_val
+ as_fn_arith $at_duration_s % 60 && at_duration_s=$as_val
+ as_fn_arith $at_duration_m % 60 && at_duration_m=$as_val
+ at_duration="${at_duration_h}h ${at_duration_m}m ${at_duration_s}s"
+ printf "%s\n" "$as_me: test suite duration: $at_duration" >&5
+ ;;
+esac
+
+echo
+printf "%s\n" "## ------------- ##
+## Test results. ##
+## ------------- ##"
+echo
+{
+ echo
+ printf "%s\n" "## ------------- ##
+## Test results. ##
+## ------------- ##"
+ echo
+} >&5
+
+if test $at_run_count = 1; then
+ at_result="1 test"
+ at_were=was
+else
+ at_result="$at_run_count tests"
+ at_were=were
+fi
+if $at_errexit_p && test $at_unexpected_count != 0; then
+ if test $at_xpass_count = 1; then
+ at_result="$at_result $at_were run, one passed"
+ else
+ at_result="$at_result $at_were run, one failed"
+ fi
+ at_result="$at_result unexpectedly and inhibited subsequent tests."
+ at_color=$at_red
+else
+ # Don't you just love exponential explosion of the number of cases?
+ at_color=$at_red
+ case $at_xpass_count:$at_fail_count:$at_xfail_count in
+ # So far, so good.
+ 0:0:0) at_result="$at_result $at_were successful." at_color=$at_grn ;;
+ 0:0:*) at_result="$at_result behaved as expected." at_color=$at_lgn ;;
+
+ # Some unexpected failures
+ 0:*:0) at_result="$at_result $at_were run,
+$at_fail_count failed unexpectedly." ;;
+
+ # Some failures, both expected and unexpected
+ 0:*:1) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+ 0:*:*) at_result="$at_result $at_were run,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+
+ # No unexpected failures, but some xpasses
+ *:0:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly." ;;
+
+ # No expected failures, but failures and xpasses
+ *:1:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failure)." ;;
+ *:*:0) at_result="$at_result $at_were run,
+$at_unexpected_count did not behave as expected ($at_fail_count unexpected failures)." ;;
+
+ # All of them.
+ *:*:1) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failure)." ;;
+ *:*:*) at_result="$at_result $at_were run,
+$at_xpass_count passed unexpectedly,
+$at_total_fail_count failed ($at_xfail_count expected failures)." ;;
+ esac
+
+ if test $at_skip_count = 0 && test $at_run_count -gt 1; then
+ at_result="All $at_result"
+ fi
+fi
+
+# Now put skips in the mix.
+case $at_skip_count in
+ 0) ;;
+ 1) at_result="$at_result
+1 test was skipped." ;;
+ *) at_result="$at_result
+$at_skip_count tests were skipped." ;;
+esac
+
+if test $at_unexpected_count = 0; then
+ echo "$at_color$at_result$at_std"
+ echo "$at_result" >&5
+else
+ echo "${at_color}ERROR: $at_result$at_std" >&2
+ echo "ERROR: $at_result" >&5
+ {
+ echo
+ printf "%s\n" "## ------------------------ ##
+## Summary of the failures. ##
+## ------------------------ ##"
+
+ # Summary of failed and skipped tests.
+ if test $at_fail_count != 0; then
+ echo "Failed tests:"
+ $SHELL "$at_myself" $at_fail_list --list
+ echo
+ fi
+ if test $at_skip_count != 0; then
+ echo "Skipped tests:"
+ $SHELL "$at_myself" $at_skip_list --list
+ echo
+ fi
+ if test $at_xpass_count != 0; then
+ echo "Unexpected passes:"
+ $SHELL "$at_myself" $at_xpass_list --list
+ echo
+ fi
+ if test $at_fail_count != 0; then
+ printf "%s\n" "## ---------------------- ##
+## Detailed failed tests. ##
+## ---------------------- ##"
+ echo
+ for at_group in $at_fail_list
+ do
+ at_group_normalized=$at_group
+
+ eval 'while :; do
+ case $at_group_normalized in #(
+ '"$at_format"'*) break;;
+ esac
+ at_group_normalized=0$at_group_normalized
+ done'
+
+ cat "$at_suite_dir/$at_group_normalized/$as_me.log"
+ echo
+ done
+ echo
+ fi
+ if test -n "$at_top_srcdir"; then
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## ${at_top_build_prefix}config.log ##
+_ASBOX
+ sed 's/^/| /' ${at_top_build_prefix}config.log
+ echo
+ fi
+ } >&5
+
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## $as_me.log was created. ##
+_ASBOX
+
+ echo
+ if $at_debug_p; then
+ at_msg='per-test log files'
+ else
+ at_msg="\`${at_testdir+${at_testdir}/}$as_me.log'"
+ fi
+ at_msg1a=${at_xpass_list:+', '}
+ at_msg1=$at_fail_list${at_fail_list:+" failed$at_msg1a"}
+ at_msg2=$at_xpass_list${at_xpass_list:+" passed unexpectedly"}
+
+ printf "%s\n" "Please send $at_msg and all information you think might help:
+
+ To: <debian-dpkg@lists.debian.org>
+ Subject: [dpkg 1.21.22] $as_me: $at_msg1$at_msg2
+
+You may investigate any problem if you feel able to do so, in which
+case the test suite provides a good starting point. Its output may
+be found below \`${at_testdir+${at_testdir}/}$as_me.dir'.
+"
+ exit 1
+fi
+
+exit 0
+
+## ------------- ##
+## Actual tests. ##
+## ------------- ##
+#AT_START_1
+at_fn_group_banner 1 'deb-format.at:1' \
+ "dpkg-deb options" " " 1
+at_xfail=no
+(
+ printf "%s\n" "1. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:4: dpkg-deb --version"
+at_fn_check_prepare_trace "deb-format.at:4"
+( $at_check_trace; dpkg-deb --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:4"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:5: dpkg-deb --help"
+at_fn_check_prepare_trace "deb-format.at:5"
+( $at_check_trace; dpkg-deb --help
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_1
+#AT_START_2
+at_fn_group_banner 2 'deb-format.at:10' \
+ "dpkg-deb .deb format 0.93x" " " 1
+at_xfail=no
+(
+ printf "%s\n" "2. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "deb-format.at:13" >"$at_check_line_file"
+(! command -v gzip >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:13"
+
+cat >pkg-deb-old-bogus-only-version.deb <<'_ATEOF'
+0.93
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:17:
+# Check truncated old deb w/ only version magic
+dpkg-deb --info pkg-deb-old-bogus-only-version.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:17"
+( $at_check_trace;
+# Check truncated old deb w/ only version magic
+dpkg-deb --info pkg-deb-old-bogus-only-version.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: unexpected end of file in archive control member size in pkg-deb-old-bogus-only-version.deb
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:17"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-deb-old-format/DEBIAN'
+
+ cat >'pkg-deb-old-format/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-deb-old-format
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ $SED -e 's/^Description:.*$/& - deb old format support/' <'pkg-deb-old-format/DEBIAN/control' >'pkg-deb-old-format/DEBIAN/control.new'
+ mv 'pkg-deb-old-format/DEBIAN/control.new' 'pkg-deb-old-format/DEBIAN/control'
+
+cat >pkg-deb-old-format/file-templ <<'_ATEOF'
+test
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:28:
+# Initialize the template package
+mv pkg-deb-old-format pkg-old-templ
+cp \$top_srcdir/ChangeLog.old pkg-old-templ/
+chmod 0644 pkg-old-templ/ChangeLog.old
+chmod -R u+w pkg-old-templ
+find pkg-old-templ | xargs touch -t 197001010100.00
+dpkg-deb --deb-format=0.939000 --root-owner-group -Zgzip -b pkg-old-templ >/dev/null
+
+dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar
+gzip -n fsys.tar
+
+# Create deb-old 0.939
+cp pkg-old-templ.deb pkg-old.deb
+
+# Create deb-old-old-old 0.931
+mkdir -p pkg-old-0931-templ/.DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0931-templ/.DEBIAN/
+find pkg-old-0931-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0931.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0931-templ .DEBIAN
+
+echo '0.931000' >pkg-old-0931.deb
+
+ \$PERL -E 'say -s shift' \"ctrl-0931.tar.gz\" >>pkg-old-0931.deb
+cat ctrl-0931.tar.gz >>pkg-old-0931.deb
+cat fsys.tar.gz >>pkg-old-0931.deb
+
+# Create deb-old-old template
+mkdir -p pkg-old-0932-templ/DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0932-templ/DEBIAN/
+find pkg-old-0932-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0932.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0932-templ DEBIAN
+
+# Create deb-old-old 0.932
+echo '0.932000' >pkg-old-0932.deb
+
+ \$PERL -E 'say -s shift' \"ctrl-0932.tar.gz\" >>pkg-old-0932.deb
+cat ctrl-0932.tar.gz >>pkg-old-0932.deb
+cat fsys.tar.gz >>pkg-old-0932.deb
+
+# Create deb-old-old 0.933
+echo '0.933000' >pkg-old-0933.deb
+
+ \$PERL -E 'say -s shift' \"ctrl-0932.tar.gz\" >>pkg-old-0933.deb
+cat ctrl-0932.tar.gz >>pkg-old-0933.deb
+cat fsys.tar.gz >>pkg-old-0933.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:28"
+( $at_check_trace;
+# Initialize the template package
+mv pkg-deb-old-format pkg-old-templ
+cp $top_srcdir/ChangeLog.old pkg-old-templ/
+chmod 0644 pkg-old-templ/ChangeLog.old
+chmod -R u+w pkg-old-templ
+find pkg-old-templ | xargs touch -t 197001010100.00
+dpkg-deb --deb-format=0.939000 --root-owner-group -Zgzip -b pkg-old-templ >/dev/null
+
+dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar
+gzip -n fsys.tar
+
+# Create deb-old 0.939
+cp pkg-old-templ.deb pkg-old.deb
+
+# Create deb-old-old-old 0.931
+mkdir -p pkg-old-0931-templ/.DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0931-templ/.DEBIAN/
+find pkg-old-0931-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0931.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0931-templ .DEBIAN
+
+echo '0.931000' >pkg-old-0931.deb
+
+ $PERL -E 'say -s shift' "ctrl-0931.tar.gz" >>pkg-old-0931.deb
+cat ctrl-0931.tar.gz >>pkg-old-0931.deb
+cat fsys.tar.gz >>pkg-old-0931.deb
+
+# Create deb-old-old template
+mkdir -p pkg-old-0932-templ/DEBIAN
+cp pkg-old-templ/DEBIAN/* pkg-old-0932-templ/DEBIAN/
+find pkg-old-0932-templ | xargs touch -t 197001010100.00
+tar czf ctrl-0932.tar.gz --format=gnu --mtime @0 --clamp-mtime --owner root:0 --group root:0 -C pkg-old-0932-templ DEBIAN
+
+# Create deb-old-old 0.932
+echo '0.932000' >pkg-old-0932.deb
+
+ $PERL -E 'say -s shift' "ctrl-0932.tar.gz" >>pkg-old-0932.deb
+cat ctrl-0932.tar.gz >>pkg-old-0932.deb
+cat fsys.tar.gz >>pkg-old-0932.deb
+
+# Create deb-old-old 0.933
+echo '0.933000' >pkg-old-0933.deb
+
+ $PERL -E 'say -s shift' "ctrl-0932.tar.gz" >>pkg-old-0933.deb
+cat ctrl-0932.tar.gz >>pkg-old-0933.deb
+cat fsys.tar.gz >>pkg-old-0933.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:73:
+# Check old package metadata
+dpkg-deb -I pkg-old.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:73"
+( $at_check_trace;
+# Check old package metadata
+dpkg-deb -I pkg-old.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" " old Debian package, version 0.939000.
+ size 174621 bytes: control archive=274, main archive=174334.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:88:
+# Check old package metadata
+dpkg-deb -I pkg-old-0931.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:88"
+( $at_check_trace;
+# Check old package metadata
+dpkg-deb -I pkg-old-0931.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" " old Debian package, version 0.931000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:88"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:103:
+# Check old package metadata
+dpkg-deb -I pkg-old-0932.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:103"
+( $at_check_trace;
+# Check old package metadata
+dpkg-deb -I pkg-old-0932.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" " old Debian package, version 0.932000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:103"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:118:
+# Check old package metadata
+dpkg-deb -I pkg-old-0933.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:118"
+( $at_check_trace;
+# Check old package metadata
+dpkg-deb -I pkg-old-0933.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" " old Debian package, version 0.933000.
+ size 175522 bytes: control archive=291, main archive=175218.
+ 201 bytes, 7 lines control
+ Package: pkg-deb-old-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb old format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:118"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:133:
+# Check old package contents
+dpkg-deb -c pkg-old.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:133"
+( $at_check_trace;
+# Check old package contents
+dpkg-deb -c pkg-old.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:133"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:141:
+# Check old package contents
+dpkg-deb -c pkg-old-0931.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:141"
+( $at_check_trace;
+# Check old package contents
+dpkg-deb -c pkg-old-0931.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:141"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:149:
+# Check old package contents
+dpkg-deb -c pkg-old-0932.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:149"
+( $at_check_trace;
+# Check old package contents
+dpkg-deb -c pkg-old-0932.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:149"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:157:
+# Check old package contents
+dpkg-deb -c pkg-old-0933.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:157"
+( $at_check_trace;
+# Check old package contents
+dpkg-deb -c pkg-old-0933.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:157"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_2
+#AT_START_3
+at_fn_group_banner 3 'deb-format.at:168' \
+ "dpkg-deb .deb format 2.x" " " 1
+at_xfail=no
+(
+ printf "%s\n" "3. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "deb-format.at:171" >"$at_check_line_file"
+(! command -v xz >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:171"
+printf "%s\n" "deb-format.at:172" >"$at_check_line_file"
+(! command -v gzip >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:172"
+printf "%s\n" "deb-format.at:173" >"$at_check_line_file"
+(! command -v zstd >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:173"
+printf "%s\n" "deb-format.at:174" >"$at_check_line_file"
+(! command -v bzip2 >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:174"
+printf "%s\n" "deb-format.at:175" >"$at_check_line_file"
+(! command -v lzma >/dev/null) \
+ && at_fn_check_skip 77 "$at_srcdir/deb-format.at:175"
+
+: >pkg-deb-bogus-empty.deb
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:178:
+# Check truncated deb w/ 0 size
+dpkg-deb --info pkg-deb-bogus-empty.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:178"
+( $at_check_trace;
+# Check truncated deb w/ 0 size
+dpkg-deb --info pkg-deb-bogus-empty.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: unexpected end of file in archive magic version number in pkg-deb-bogus-empty.deb
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:178"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-deb-format/DEBIAN'
+
+ cat >'pkg-deb-format/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-deb-format
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ $SED -e 's/^Description:.*$/& - deb format support/' <'pkg-deb-format/DEBIAN/control' >'pkg-deb-format/DEBIAN/control.new'
+ mv 'pkg-deb-format/DEBIAN/control.new' 'pkg-deb-format/DEBIAN/control'
+
+cat >pkg-deb-format/file-templ <<'_ATEOF'
+test
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:189:
+# Initialize the template package
+mv pkg-deb-format pkg-templ
+cp \$top_srcdir/ChangeLog.old pkg-templ/
+chmod 0644 pkg-templ/ChangeLog.old
+chmod -R u+w pkg-templ
+find pkg-templ | xargs touch -t 197001010100.00
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ >/dev/null
+
+# Extract the base members
+ar x pkg-templ.deb
+gzip -c control.tar >control.tar.gz
+gzip -c data.tar >data.tar.gz
+xz -c control.tar >control.tar.xz
+xz -c data.tar >data.tar.xz
+zstd -c control.tar >control.tar.zst
+zstd -c data.tar >data.tar.zst
+bzip2 -c data.tar >data.tar.bz2
+lzma -c data.tar >data.tar.lzma
+touch _ignore
+touch unknown
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:189"
+( $at_check_trace;
+# Initialize the template package
+mv pkg-deb-format pkg-templ
+cp $top_srcdir/ChangeLog.old pkg-templ/
+chmod 0644 pkg-templ/ChangeLog.old
+chmod -R u+w pkg-templ
+find pkg-templ | xargs touch -t 197001010100.00
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ >/dev/null
+
+# Extract the base members
+ar x pkg-templ.deb
+gzip -c control.tar >control.tar.gz
+gzip -c data.tar >data.tar.gz
+xz -c control.tar >control.tar.xz
+xz -c data.tar >data.tar.xz
+zstd -c control.tar >control.tar.zst
+zstd -c data.tar >data.tar.zst
+bzip2 -c data.tar >data.tar.bz2
+lzma -c data.tar >data.tar.lzma
+touch _ignore
+touch unknown
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:212:
+# Test debian-binary with 2.x versions
+cp pkg-templ.deb pkg-version-2x.deb
+echo 2.999 >debian-binary
+ar rc pkg-version-2x.deb debian-binary
+ar t pkg-version-2x.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-version-2x.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:212"
+( $at_check_trace;
+# Test debian-binary with 2.x versions
+cp pkg-templ.deb pkg-version-2x.deb
+echo 2.999 >debian-binary
+ar rc pkg-version-2x.deb debian-binary
+ar t pkg-version-2x.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-version-2x.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.999.
+ size 655554 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:212"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:236:
+# Test debian-binary with extra lines
+cp pkg-templ.deb pkg-magic-extra.deb
+echo \"extra line\" >>debian-binary
+ar rc pkg-magic-extra.deb debian-binary
+ar t pkg-magic-extra.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-magic-extra.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:236"
+( $at_check_trace;
+# Test debian-binary with extra lines
+cp pkg-templ.deb pkg-magic-extra.deb
+echo "extra line" >>debian-binary
+ar rc pkg-magic-extra.deb debian-binary
+ar t pkg-magic-extra.deb
+ar x pkg-templ.deb debian-binary
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-magic-extra.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655564 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:236"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:260:
+# Test missing debian-binary member
+cp pkg-templ.deb pkg-missing-magic.deb
+ar d pkg-missing-magic.deb debian-binary
+ar t pkg-missing-magic.deb
+dpkg-deb -I pkg-missing-magic.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:260"
+( $at_check_trace;
+# Test missing debian-binary member
+cp pkg-templ.deb pkg-missing-magic.deb
+ar d pkg-missing-magic.deb debian-binary
+ar t pkg-missing-magic.deb
+dpkg-deb -I pkg-missing-magic.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: file 'pkg-missing-magic.deb' is not a Debian binary archive (try dpkg-split?)
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "control.tar
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:260"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:271:
+# Test missing control member
+cp pkg-templ.deb pkg-missing-control.deb
+ar d pkg-missing-control.deb control.tar
+ar t pkg-missing-control.deb
+dpkg-deb -I pkg-missing-control.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:271"
+( $at_check_trace;
+# Test missing control member
+cp pkg-templ.deb pkg-missing-control.deb
+ar d pkg-missing-control.deb control.tar
+ar t pkg-missing-control.deb
+dpkg-deb -I pkg-missing-control.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-missing-control.deb' has premature member 'data.tar' before 'control.tar', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:271"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:282:
+# Test missing data member
+cp pkg-templ.deb pkg-missing-data.deb
+ar d pkg-missing-data.deb data.tar
+ar t pkg-missing-data.deb
+dpkg-deb -c pkg-missing-data.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:282"
+( $at_check_trace;
+# Test missing data member
+cp pkg-templ.deb pkg-missing-data.deb
+ar d pkg-missing-data.deb data.tar
+ar t pkg-missing-data.deb
+dpkg-deb -c pkg-missing-data.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: unexpected end of file in archive member header in pkg-missing-data.deb
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:282"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:293:
+# Test duplicate debian-binary member
+cp pkg-templ.deb pkg-duplicate-magic.deb
+ar ra debian-binary pkg-duplicate-magic.deb debian-binary debian-binary
+ar t pkg-duplicate-magic.deb
+dpkg-deb -I pkg-duplicate-magic.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:293"
+( $at_check_trace;
+# Test duplicate debian-binary member
+cp pkg-templ.deb pkg-duplicate-magic.deb
+ar ra debian-binary pkg-duplicate-magic.deb debian-binary debian-binary
+ar t pkg-duplicate-magic.deb
+dpkg-deb -I pkg-duplicate-magic.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-duplicate-magic.deb' has premature member 'debian-binary' before 'control.tar', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+debian-binary
+control.tar
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:293"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:306:
+# Test duplicate control member
+cp pkg-templ.deb pkg-duplicate-control.deb
+ar ra control.tar pkg-duplicate-control.deb control.tar control.tar
+ar t pkg-duplicate-control.deb
+dpkg-deb -c pkg-duplicate-control.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:306"
+( $at_check_trace;
+# Test duplicate control member
+cp pkg-templ.deb pkg-duplicate-control.deb
+ar ra control.tar pkg-duplicate-control.deb control.tar control.tar
+ar t pkg-duplicate-control.deb
+dpkg-deb -c pkg-duplicate-control.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-duplicate-control.deb' contains two control members, giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+control.tar
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:306"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:319:
+# Test mixed member (index 1)
+cp pkg-templ.deb pkg-mixed-1-member.deb
+ar ra debian-binary pkg-mixed-1-member.deb unknown
+ar t pkg-mixed-1-member.deb
+dpkg-deb -I pkg-mixed-1-member.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:319"
+( $at_check_trace;
+# Test mixed member (index 1)
+cp pkg-templ.deb pkg-mixed-1-member.deb
+ar ra debian-binary pkg-mixed-1-member.deb unknown
+ar t pkg-mixed-1-member.deb
+dpkg-deb -I pkg-mixed-1-member.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-mixed-1-member.deb' has premature member 'unknown' before 'control.tar', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+unknown
+control.tar
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:319"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:332:
+# Test mixed member (index 2)
+cp pkg-templ.deb pkg-mixed-2-member.deb
+ar ra control.tar pkg-mixed-2-member.deb unknown
+ar t pkg-mixed-2-member.deb
+dpkg-deb -c pkg-mixed-2-member.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:332"
+( $at_check_trace;
+# Test mixed member (index 2)
+cp pkg-templ.deb pkg-mixed-2-member.deb
+ar ra control.tar pkg-mixed-2-member.deb unknown
+ar t pkg-mixed-2-member.deb
+dpkg-deb -c pkg-mixed-2-member.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-mixed-2-member.deb' has premature member 'unknown' before 'data.tar', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+unknown
+data.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:332"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:345:
+# Test swapped control and data members
+cp pkg-templ.deb pkg-swap-members.deb
+ar ma data.tar pkg-swap-members.deb control.tar
+ar t pkg-swap-members.deb
+dpkg-deb -I pkg-swap-members.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:345"
+( $at_check_trace;
+# Test swapped control and data members
+cp pkg-templ.deb pkg-swap-members.deb
+ar ma data.tar pkg-swap-members.deb control.tar
+ar t pkg-swap-members.deb
+dpkg-deb -I pkg-swap-members.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-swap-members.deb' has premature member 'data.tar' before 'control.tar', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+data.tar
+control.tar
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:345"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:357:
+# Test extra member
+cp pkg-templ.deb pkg-extra-member.deb
+ar q pkg-extra-member.deb unknown
+ar t pkg-extra-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-extra-member.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:357"
+( $at_check_trace;
+# Test extra member
+cp pkg-templ.deb pkg-extra-member.deb
+ar q pkg-extra-member.deb unknown
+ar t pkg-extra-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-extra-member.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+data.tar
+unknown
+ new Debian package, version 2.0.
+ size 655612 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:357"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:380:
+# Test _ member
+cp pkg-templ.deb pkg-under-member.deb
+ar ra debian-binary pkg-under-member.deb _ignore
+ar t pkg-under-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-under-member.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:380"
+( $at_check_trace;
+# Test _ member
+cp pkg-templ.deb pkg-under-member.deb
+ar ra debian-binary pkg-under-member.deb _ignore
+ar t pkg-under-member.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-under-member.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+_ignore
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655612 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:380"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:403:
+# Test data.tar.bad member
+dd if=/dev/zero of=data.tar.bad bs=1K count=4 status=none
+ar rc pkg-data-bad.deb debian-binary control.tar.gz data.tar.bad
+ar t pkg-data-bad.deb
+dpkg-deb -c pkg-data-bad.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:403"
+( $at_check_trace;
+# Test data.tar.bad member
+dd if=/dev/zero of=data.tar.bad bs=1K count=4 status=none
+ar rc pkg-data-bad.deb debian-binary control.tar.gz data.tar.bad
+ar t pkg-data-bad.deb
+dpkg-deb -c pkg-data-bad.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: archive 'pkg-data-bad.deb' uses unknown compression for member 'data.tar.bad', giving up
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.bad
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-format.at:403"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:415:
+# Test control.tar member
+ar rc pkg-control-none.deb debian-binary control.tar data.tar
+ar t pkg-control-none.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-control-none.deb | \$SED -e 's/ *\$//'
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:415"
+( $at_check_trace;
+# Test control.tar member
+ar rc pkg-control-none.deb debian-binary control.tar data.tar
+ar t pkg-control-none.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-control-none.deb | $SED -e 's/ *$//'
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar
+data.tar
+ new Debian package, version 2.0.
+ size 655552 bytes: control archive=10240 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:415"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:436:
+# Test control.tar.xz member
+ar rc pkg-control-xz.deb debian-binary control.tar.xz data.tar.xz
+ar t pkg-control-xz.deb
+dpkg-deb -c pkg-control-xz.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:436"
+( $at_check_trace;
+# Test control.tar.xz member
+ar rc pkg-control-xz.deb debian-binary control.tar.xz data.tar.xz
+ar t pkg-control-xz.deb
+dpkg-deb -c pkg-control-xz.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.xz
+data.tar.xz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:436"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:449:
+# Test control.tar.zst member
+ar rc pkg-control-zst.deb debian-binary control.tar.zst data.tar.zst
+ar t pkg-control-zst.deb
+dpkg-deb -c pkg-control-zst.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:449"
+( $at_check_trace;
+# Test control.tar.zst member
+ar rc pkg-control-zst.deb debian-binary control.tar.zst data.tar.zst
+ar t pkg-control-zst.deb
+dpkg-deb -c pkg-control-zst.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.zst
+data.tar.zst
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:449"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:462:
+# Test data.tar member
+ar rc pkg-data-none.deb debian-binary control.tar.gz data.tar
+ar t pkg-data-none.deb
+dpkg-deb -c pkg-data-none.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:462"
+( $at_check_trace;
+# Test data.tar member
+ar rc pkg-data-none.deb debian-binary control.tar.gz data.tar
+ar t pkg-data-none.deb
+dpkg-deb -c pkg-data-none.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:462"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:475:
+# Test data.tar.gz member
+ar rc pkg-data-gz.deb debian-binary control.tar.gz data.tar.gz
+ar t pkg-data-gz.deb
+dpkg-deb -c pkg-data-gz.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:475"
+( $at_check_trace;
+# Test data.tar.gz member
+ar rc pkg-data-gz.deb debian-binary control.tar.gz data.tar.gz
+ar t pkg-data-gz.deb
+dpkg-deb -c pkg-data-gz.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.gz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:475"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:488:
+# Test data.tar.xz member
+ar rc pkg-data-xz.deb debian-binary control.tar.gz data.tar.xz
+ar t pkg-data-xz.deb
+dpkg-deb -c pkg-data-xz.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:488"
+( $at_check_trace;
+# Test data.tar.xz member
+ar rc pkg-data-xz.deb debian-binary control.tar.gz data.tar.xz
+ar t pkg-data-xz.deb
+dpkg-deb -c pkg-data-xz.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.xz
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:488"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:501:
+# Test data.tar.zst member
+ar rc pkg-data-zst.deb debian-binary control.tar.gz data.tar.zst
+ar t pkg-data-zst.deb
+dpkg-deb -c pkg-data-zst.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:501"
+( $at_check_trace;
+# Test data.tar.zst member
+ar rc pkg-data-zst.deb debian-binary control.tar.gz data.tar.zst
+ar t pkg-data-zst.deb
+dpkg-deb -c pkg-data-zst.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.zst
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:501"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:514:
+# Test data.tar.bz2 member
+ar rc pkg-data-bz2.deb debian-binary control.tar.gz data.tar.bz2
+ar t pkg-data-bz2.deb
+dpkg-deb -c pkg-data-bz2.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:514"
+( $at_check_trace;
+# Test data.tar.bz2 member
+ar rc pkg-data-bz2.deb debian-binary control.tar.gz data.tar.bz2
+ar t pkg-data-bz2.deb
+dpkg-deb -c pkg-data-bz2.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.bz2
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:514"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:527:
+# Test data.tar.lzma member
+ar rc pkg-data-lzma.deb debian-binary control.tar.gz data.tar.lzma
+ar t pkg-data-lzma.deb
+dpkg-deb -c pkg-data-lzma.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:527"
+( $at_check_trace;
+# Test data.tar.lzma member
+ar rc pkg-data-lzma.deb debian-binary control.tar.gz data.tar.lzma
+ar t pkg-data-lzma.deb
+dpkg-deb -c pkg-data-lzma.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.gz
+data.tar.lzma
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:527"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:540:
+# Test non-uniform data.tar/control.tar member compression
+ar rc pkg-mixed-comp.deb debian-binary control.tar.xz data.tar.gz
+ar t pkg-mixed-comp.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-mixed-comp.deb | \$SED -e 's/ *\$//'
+dpkg-deb -c pkg-mixed-comp.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:540"
+( $at_check_trace;
+# Test non-uniform data.tar/control.tar member compression
+ar rc pkg-mixed-comp.deb debian-binary control.tar.xz data.tar.gz
+ar t pkg-mixed-comp.deb
+# XXX: Ideally we would have no need to strip trailing spaces.
+dpkg-deb -I pkg-mixed-comp.deb | $SED -e 's/ *$//'
+dpkg-deb -c pkg-mixed-comp.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-binary
+control.tar.xz
+data.tar.gz
+ new Debian package, version 2.0.
+ size 175756 bytes: control archive=336 bytes.
+ 193 bytes, 7 lines control
+ Package: pkg-deb-format
+ Version: 0.0-1
+ Section: test
+ Priority: extra
+ Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+ Architecture: all
+ Description: test package - deb format support
+drwxr-xr-x root/root 0 1970-01-01 00:00 ./
+-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old
+-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:540"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:565:
+# Test building and extracting none compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ pkg-comp-none.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-none.deb >ctrl-none.tar
+dpkg-deb --fsys-tarfile pkg-comp-none.deb >fsys-none.tar
+cmp ctrl-none.tar control.tar
+cmp fsys-none.tar data.tar
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:565"
+( $at_check_trace;
+# Test building and extracting none compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Znone -b pkg-templ pkg-comp-none.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-none.deb >ctrl-none.tar
+dpkg-deb --fsys-tarfile pkg-comp-none.deb >fsys-none.tar
+cmp ctrl-none.tar control.tar
+cmp fsys-none.tar data.tar
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:565"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:574:
+# Test building and extracting gzip compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zgzip -b pkg-templ pkg-comp-gzip.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-gzip.deb >ctrl-gzip.tar
+dpkg-deb --fsys-tarfile pkg-comp-gzip.deb >fsys-gzip.tar
+cmp ctrl-gzip.tar control.tar
+cmp fsys-gzip.tar data.tar
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:574"
+( $at_check_trace;
+# Test building and extracting gzip compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zgzip -b pkg-templ pkg-comp-gzip.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-gzip.deb >ctrl-gzip.tar
+dpkg-deb --fsys-tarfile pkg-comp-gzip.deb >fsys-gzip.tar
+cmp ctrl-gzip.tar control.tar
+cmp fsys-gzip.tar data.tar
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:574"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:583:
+# Test building and extracting xz compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zxz -b pkg-templ pkg-comp-xz.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-xz.deb >ctrl-xz.tar
+dpkg-deb --fsys-tarfile pkg-comp-xz.deb >fsys-xz.tar
+cmp ctrl-xz.tar control.tar
+cmp fsys-xz.tar data.tar
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:583"
+( $at_check_trace;
+# Test building and extracting xz compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zxz -b pkg-templ pkg-comp-xz.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-xz.deb >ctrl-xz.tar
+dpkg-deb --fsys-tarfile pkg-comp-xz.deb >fsys-xz.tar
+cmp ctrl-xz.tar control.tar
+cmp fsys-xz.tar data.tar
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:583"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-format.at:592:
+# Test building and extracting zstd compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zzstd -b pkg-templ pkg-comp-zstd.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-zstd.deb >ctrl-zstd.tar
+dpkg-deb --fsys-tarfile pkg-comp-zstd.deb >fsys-zstd.tar
+cmp ctrl-zstd.tar control.tar
+cmp fsys-zstd.tar data.tar
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:592"
+( $at_check_trace;
+# Test building and extracting zstd compressed archive
+dpkg-deb --uniform-compression --root-owner-group -Zzstd -b pkg-templ pkg-comp-zstd.deb >/dev/null
+dpkg-deb --ctrl-tarfile pkg-comp-zstd.deb >ctrl-zstd.tar
+dpkg-deb --fsys-tarfile pkg-comp-zstd.deb >fsys-zstd.tar
+cmp ctrl-zstd.tar control.tar
+cmp fsys-zstd.tar data.tar
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-format.at:592"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_3
+#AT_START_4
+at_fn_group_banner 4 'deb-content.at:1' \
+ "dpkg-deb .deb conffiles" " " 1
+at_xfail=no
+(
+ printf "%s\n" "4. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+
+ mkdir -p 'pkg-conff-duped/DEBIAN'
+
+ cat >'pkg-conff-duped/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-duped
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-duped/DEBIAN'
+
+ cat >'pkg-conff-duped/DEBIAN/conffiles' <<CTRL_TEMPL
+/test-conffile-1
+/test-conffile-2
+/test-conffile-1
+CTRL_TEMPL
+
+cat >pkg-conff-duped/test-conffile-1 <<'_ATEOF'
+test init
+_ATEOF
+
+cat >pkg-conff-duped/test-conffile-2 <<'_ATEOF'
+test init
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:12:
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-duped
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:12"
+( $at_check_trace;
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-duped
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: warning: conffile name '/test-conffile-1' is duplicated
+dpkg-deb: warning: ignoring 1 warning about the control file(s)
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-content.at:12"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-noeol/DEBIAN'
+
+ cat >'pkg-conff-noeol/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-noeol
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+printf "/test-conffile-1" >"pkg-conff-noeol/DEBIAN/conffiles"
+cat >pkg-conff-noeol/test-conffile-1 <<'_ATEOF'
+test init
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:23:
+# Conffiles need a final newline to guarantee there's been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-noeol pkg-conff-noeol.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:23"
+( $at_check_trace;
+# Conffiles need a final newline to guarantee there's been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-noeol pkg-conff-noeol.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile name '/test-conffile-1' is too long, or missing final newline
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:23"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-noabs/DEBIAN'
+
+ cat >'pkg-conff-noabs/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-noabs
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-noabs/DEBIAN'
+
+ cat >'pkg-conff-noabs/DEBIAN/conffiles' <<CTRL_TEMPL
+test-conffile-rel
+CTRL_TEMPL
+
+cat >pkg-conff-noabs/test-conffile-rel <<'_ATEOF'
+test init
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:34:
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-noabs pkg-conff-noabs.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:34"
+( $at_check_trace;
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-noabs pkg-conff-noabs.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile name 'test-conffile-rel' is not an absolute pathname
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-empty/DEBIAN'
+
+ cat >'pkg-conff-empty/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-empty
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+printf " \n" >"pkg-conff-empty/DEBIAN/conffiles"
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:42:
+# Conffiles must not contain empty lines.
+dpkg-deb -b pkg-conff-empty pkg-conff-empty.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:42"
+( $at_check_trace;
+# Conffiles must not contain empty lines.
+dpkg-deb -b pkg-conff-empty pkg-conff-empty.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: empty and whitespace-only lines are not allowed in conffiles
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-space-prefix/DEBIAN'
+
+ cat >'pkg-conff-space-prefix/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-space-prefix
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-space-prefix/DEBIAN'
+
+ cat >'pkg-conff-space-prefix/DEBIAN/conffiles' <<CTRL_TEMPL
+ /test-conffile
+CTRL_TEMPL
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:50:
+# Conffiles must not contain prefixed spaces.
+dpkg-deb -b pkg-conff-space-prefix pkg-conff-space-prefix.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:50"
+( $at_check_trace;
+# Conffiles must not contain prefixed spaces.
+dpkg-deb -b pkg-conff-space-prefix pkg-conff-space-prefix.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: line with conffile filename '/test-conffile' has leading white spaces
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:50"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-unknown-flag/DEBIAN'
+
+ cat >'pkg-conff-unknown-flag/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-unknown-flag
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-unknown-flag/DEBIAN'
+
+ cat >'pkg-conff-unknown-flag/DEBIAN/conffiles' <<CTRL_TEMPL
+unknown-flag /test-conffile
+CTRL_TEMPL
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:58:
+# Conffiles marked with an unknown flag.
+dpkg-deb -b pkg-conff-unknown-flag pkg-conff-unknown-flag.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:58"
+( $at_check_trace;
+# Conffiles marked with an unknown flag.
+dpkg-deb -b pkg-conff-unknown-flag pkg-conff-unknown-flag.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: unknown flag 'unknown-flag' for conffile '/test-conffile'
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:58"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-missing-pathname/DEBIAN'
+
+ cat >'pkg-conff-missing-pathname/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-missing-pathname
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+printf "unknown-flag \n" >"pkg-conff-missing-pathname/DEBIAN/conffiles"
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:66:
+# Conffiles need a pathname, in addition to a flag.
+dpkg-deb -b pkg-conff-missing-pathname pkg-conff-missing-pathname.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:66"
+( $at_check_trace;
+# Conffiles need a pathname, in addition to a flag.
+dpkg-deb -b pkg-conff-missing-pathname pkg-conff-missing-pathname.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile name missing after flag 'unknown-flag'
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:66"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-removed-missing/DEBIAN'
+
+ cat >'pkg-conff-removed-missing/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-removed-missing
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-removed-missing/DEBIAN'
+
+ cat >'pkg-conff-removed-missing/DEBIAN/conffiles' <<CTRL_TEMPL
+remove-on-upgrade /test-conffile-missing
+CTRL_TEMPL
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:74:
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-missing pkg-conff-removed-missing.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:74"
+( $at_check_trace;
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-missing pkg-conff-removed-missing.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-content.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-removed-duped/DEBIAN'
+
+ cat >'pkg-conff-removed-duped/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-removed-duped
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-removed-duped/DEBIAN'
+
+ cat >'pkg-conff-removed-duped/DEBIAN/conffiles' <<CTRL_TEMPL
+remove-on-upgrade /test-conffile-1
+remove-on-upgrade /test-conffile-2
+remove-on-upgrade /test-conffile-1
+CTRL_TEMPL
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:83:
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-removed-duped
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:83"
+( $at_check_trace;
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-removed-duped
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: warning: conffile name '/test-conffile-1' is duplicated
+dpkg-deb: warning: ignoring 1 warning about the control file(s)
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-content.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-removed-noeol/DEBIAN'
+
+ cat >'pkg-conff-removed-noeol/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-removed-noeol
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+printf "remove-on-upgrade /test-conffile-1" >"pkg-conff-removed-noeol/DEBIAN/conffiles"
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:92:
+# Conffiles need a final newline to guarantee there has been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-removed-noeol pkg-conff-removed-noeol.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:92"
+( $at_check_trace;
+# Conffiles need a final newline to guarantee there has been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-removed-noeol pkg-conff-removed-noeol.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile name 'remove-on-upgrade /test-conffile-1' is too long, or missing final newline
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:92"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-removed-noabs/DEBIAN'
+
+ cat >'pkg-conff-removed-noabs/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-removed-noabs
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-removed-noabs/DEBIAN'
+
+ cat >'pkg-conff-removed-noabs/DEBIAN/conffiles' <<CTRL_TEMPL
+remove-on-upgrade test-conffile-rel
+CTRL_TEMPL
+
+cat >pkg-conff-removed-noabs/test-conffile-rel <<'_ATEOF'
+test init
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:103:
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-removed-noabs pkg-conff-removed-noabs.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:103"
+( $at_check_trace;
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-removed-noabs pkg-conff-removed-noabs.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile name 'test-conffile-rel' is not an absolute pathname
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:103"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-conff-removed-present/DEBIAN'
+
+ cat >'pkg-conff-removed-present/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-conff-removed-present
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ mkdir -p 'pkg-conff-removed-present/DEBIAN'
+
+ cat >'pkg-conff-removed-present/DEBIAN/conffiles' <<CTRL_TEMPL
+remove-on-upgrade /test-conffile-present
+CTRL_TEMPL
+
+cat >pkg-conff-removed-present/test-conffile-present <<'_ATEOF'
+test init
+_ATEOF
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:113:
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-present pkg-conff-removed-present.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:113"
+( $at_check_trace;
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-present pkg-conff-removed-present.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: conffile '/test-conffile-present' is present but is requested to be removed
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:113"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-deb-newline/DEBIAN'
+
+ cat >'pkg-deb-newline/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-deb-newline
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+touch 'pkg-deb-newline/file
+newline'
+{ set +x
+printf "%s\n" "$at_srcdir/deb-content.at:122:
+# Cannot create package with newlines in filenames.
+dpkg-deb -b pkg-deb-newline
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-content.at:122"
+( $at_check_trace;
+# Cannot create package with newlines in filenames.
+dpkg-deb -b pkg-deb-newline
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: error: newline not allowed in pathname './file
+newline'
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/deb-content.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_4
+#AT_START_5
+at_fn_group_banner 5 'deb-fields.at:1' \
+ "dpkg-deb .deb fields" " " 1
+at_xfail=no
+(
+ printf "%s\n" "5. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+
+ mkdir -p 'pkg-package-type-void/DEBIAN'
+
+ cat >'pkg-package-type-void/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-package-type-void
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-fields.at:5:
+dpkg-deb -b pkg-package-type-void
+# Test absence of Package-Type field.
+test -z \"\$(dpkg-deb -f pkg-package-type-void.deb Package-Type)\"
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "deb-fields.at:5"
+( $at_check_trace;
+dpkg-deb -b pkg-package-type-void
+# Test absence of Package-Type field.
+test -z "$(dpkg-deb -f pkg-package-type-void.deb Package-Type)"
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-fields.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-package-type-use/DEBIAN'
+
+ cat >'pkg-package-type-use/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-package-type-use
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ $SED -e '/^Package:/aPackage-Type: udeb' <'pkg-package-type-use/DEBIAN/control' >'pkg-package-type-use/DEBIAN/control.new'
+ mv 'pkg-package-type-use/DEBIAN/control.new' 'pkg-package-type-use/DEBIAN/control'
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-fields.at:13:
+dpkg-deb -b pkg-package-type-use
+# Test presence of Package-Type field.
+test -n \"\$(dpkg-deb -f pkg-package-type-use.deb Package-Type)\"
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "deb-fields.at:13"
+( $at_check_trace;
+dpkg-deb -b pkg-package-type-use
+# Test presence of Package-Type field.
+test -n "$(dpkg-deb -f pkg-package-type-use.deb Package-Type)"
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-fields.at:13"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+
+ mkdir -p 'pkg-obsolete-fields/DEBIAN'
+
+ cat >'pkg-obsolete-fields/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-obsolete-fields
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ $SED -e 's/^Priority:/Class:/' <'pkg-obsolete-fields/DEBIAN/control' >'pkg-obsolete-fields/DEBIAN/control.new'
+ mv 'pkg-obsolete-fields/DEBIAN/control.new' 'pkg-obsolete-fields/DEBIAN/control'
+
+
+ $SED -e 's/^Version: 0.0-1/Version: 0.0/' <'pkg-obsolete-fields/DEBIAN/control' >'pkg-obsolete-fields/DEBIAN/control.new'
+ mv 'pkg-obsolete-fields/DEBIAN/control.new' 'pkg-obsolete-fields/DEBIAN/control'
+
+
+ $SED -e '/^Version:/aRevision: 1' <'pkg-obsolete-fields/DEBIAN/control' >'pkg-obsolete-fields/DEBIAN/control.new'
+ mv 'pkg-obsolete-fields/DEBIAN/control.new' 'pkg-obsolete-fields/DEBIAN/control'
+
+
+ $SED -e '/^Package:/aOptional: suggests' <'pkg-obsolete-fields/DEBIAN/control' >'pkg-obsolete-fields/DEBIAN/control.new'
+ mv 'pkg-obsolete-fields/DEBIAN/control.new' 'pkg-obsolete-fields/DEBIAN/control'
+
+
+ $SED -e '/^Package:/aRecommended: recommends' <'pkg-obsolete-fields/DEBIAN/control' >'pkg-obsolete-fields/DEBIAN/control.new'
+ mv 'pkg-obsolete-fields/DEBIAN/control.new' 'pkg-obsolete-fields/DEBIAN/control'
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-fields.at:25:
+dpkg-deb -b pkg-obsolete-fields
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-fields.at:25"
+( $at_check_trace;
+dpkg-deb -b pkg-obsolete-fields
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 2 package 'pkg-obsolete-fields':
+ obsolete 'Recommended' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 3 package 'pkg-obsolete-fields':
+ obsolete 'Optional' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 5 package 'pkg-obsolete-fields':
+ obsolete 'Revision' field used
+dpkg-deb: warning: parsing file 'pkg-obsolete-fields/DEBIAN/control' near line 7 package 'pkg-obsolete-fields':
+ obsolete 'Class' field used
+dpkg-deb: warning: ignoring 4 warnings about the control file(s)
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-fields.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-fields.at:38:
+dpkg-deb -f pkg-obsolete-fields.deb \\
+ Version Recommends Suggests Priority 2>/dev/null
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-fields.at:38"
+( $at_check_trace;
+dpkg-deb -f pkg-obsolete-fields.deb \
+ Version Recommends Suggests Priority 2>/dev/null
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "Version: 0.0-1
+Recommends: recommends
+Suggests: suggests
+Priority: extra
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-fields.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_5
+#AT_START_6
+at_fn_group_banner 6 'deb-split.at:1' \
+ "dpkg-split options" " " 2
+at_xfail=no
+(
+ printf "%s\n" "6. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:4: dpkg-split --version"
+at_fn_check_prepare_trace "deb-split.at:4"
+( $at_check_trace; dpkg-split --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:4"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:5: dpkg-split --help"
+at_fn_check_prepare_trace "deb-split.at:5"
+( $at_check_trace; dpkg-split --help
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_6
+#AT_START_7
+at_fn_group_banner 7 'deb-split.at:9' \
+ "dpkg-split .deb format" " " 2
+at_xfail=no
+(
+ printf "%s\n" "7. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+
+ mkdir -p 'pkg-split/DEBIAN'
+
+ cat >'pkg-split/DEBIAN/control' <<CTRL_TEMPL
+Package: pkg-split
+Version: 0.0-1
+Section: test
+Priority: extra
+Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
+Architecture: all
+Description: test package
+CTRL_TEMPL
+
+
+
+ $SED -e 's/^Description:.*$/& - normal package to be split/' <'pkg-split/DEBIAN/control' >'pkg-split/DEBIAN/control.new'
+ mv 'pkg-split/DEBIAN/control.new' 'pkg-split/DEBIAN/control'
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:15:
+# Initialize the template package
+chmod -R u+w pkg-split
+\$PERL -E 'print \"fade\" foreach 1 .. 1024 * 512' >pkg-split/data-file
+find pkg-split | xargs touch -t 197001010100.00
+dpkg-deb --root-owner-group -Znone -b pkg-split >/dev/null
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:15"
+( $at_check_trace;
+# Initialize the template package
+chmod -R u+w pkg-split
+$PERL -E 'print "fade" foreach 1 .. 1024 * 512' >pkg-split/data-file
+find pkg-split | xargs touch -t 197001010100.00
+dpkg-deb --root-owner-group -Znone -b pkg-split >/dev/null
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:15"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:23:
+# Test splitting a package (in 10 parts: 9 * 210 KiB B + 158 KiB)
+dpkg-split -S 210 -s pkg-split.deb pkg-split-part
+for p in \$(seq 10); do
+ test -f pkg-split-part.\${p}of10.deb
+done
+"
+at_fn_check_prepare_notrace 'a $(...) command substitution' "deb-split.at:23"
+( $at_check_trace;
+# Test splitting a package (in 10 parts: 9 * 210 KiB B + 158 KiB)
+dpkg-split -S 210 -s pkg-split.deb pkg-split-part
+for p in $(seq 10); do
+ test -f pkg-split-part.${p}of10.deb
+done
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "Splitting package pkg-split into 10 parts: 1 2 3 4 5 6 7 8 9 10 done
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:23"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+DEB_SPLIT_MD5SUM=1684b6cdb72bf035ccafd653f307d3da
+DEB_SPLIT_LENGTH=2109632
+DEB_SPLIT_PART_LENGTH=214016
+DEB_SPLIT_PART_SIZE=214222
+DEB_SPLIT_LAST_LENGTH=183488
+DEB_SPLIT_LAST_SIZE=183694
+
+DEB_SPLIT_PART_SIZE_VERSION=$((DEB_SPLIT_PART_SIZE + 2))
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:41:
+# Test debian-split with 2.x version
+cp pkg-split-part.1of10.deb pkg-split-part-version-2x.deb
+ar x pkg-split-part-version-2x.deb debian-split
+sed -e '1c2.999' debian-split >debian-split.new
+mv debian-split.new debian-split
+ar rc pkg-split-part-version-2x.deb debian-split
+ar t pkg-split-part-version-2x.deb
+dpkg-split -I pkg-split-part-version-2x.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:41"
+( $at_check_trace;
+# Test debian-split with 2.x version
+cp pkg-split-part.1of10.deb pkg-split-part-version-2x.deb
+ar x pkg-split-part-version-2x.deb debian-split
+sed -e '1c2.999' debian-split >debian-split.new
+mv debian-split.new debian-split
+ar rc pkg-split-part-version-2x.deb debian-split
+ar t pkg-split-part-version-2x.deb
+dpkg-split -I pkg-split-part-version-2x.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-split
+data.1
+pkg-split-part-version-2x.deb:
+ Part format version: 2.999
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE_VERSION bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+DEB_SPLIT_PART_SIZE_MAGIC_EXTRA=$((DEB_SPLIT_PART_SIZE + 10))
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:69:
+# Test debian-split with extra lines
+cp pkg-split-part.1of10.deb pkg-split-part-magic-extra.deb
+ar x pkg-split-part-magic-extra.deb debian-split
+echo \"extra line\" >>debian-split
+ar rc pkg-split-part-magic-extra.deb debian-split
+ar t pkg-split-part-magic-extra.deb
+dpkg-split -I pkg-split-part-magic-extra.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:69"
+( $at_check_trace;
+# Test debian-split with extra lines
+cp pkg-split-part.1of10.deb pkg-split-part-magic-extra.deb
+ar x pkg-split-part-magic-extra.deb debian-split
+echo "extra line" >>debian-split
+ar rc pkg-split-part-magic-extra.deb debian-split
+ar t pkg-split-part-magic-extra.deb
+dpkg-split -I pkg-split-part-magic-extra.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-split
+data.1
+pkg-split-part-magic-extra.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE_MAGIC_EXTRA bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:94:
+# Test missing debian-split
+cp pkg-split-part.1of10.deb pkg-split-part-missing-magic.deb
+ar d pkg-split-part-missing-magic.deb debian-split
+ar t pkg-split-part-missing-magic.deb
+dpkg-split -I pkg-split-part-missing-magic.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:94"
+( $at_check_trace;
+# Test missing debian-split
+cp pkg-split-part.1of10.deb pkg-split-part-missing-magic.deb
+ar d pkg-split-part-missing-magic.deb debian-split
+ar t pkg-split-part-missing-magic.deb
+dpkg-split -I pkg-split-part-missing-magic.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "data.1
+file 'pkg-split-part-missing-magic.deb' is not an archive part
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:94"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:104:
+# Test missing data part member
+cp pkg-split-part.1of10.deb pkg-split-part-missing-data.deb
+ar d pkg-split-part-missing-data.deb data.1
+ar t pkg-split-part-missing-data.deb
+dpkg-split -I pkg-split-part-missing-data.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:104"
+( $at_check_trace;
+# Test missing data part member
+cp pkg-split-part.1of10.deb pkg-split-part-missing-data.deb
+ar d pkg-split-part-missing-data.deb data.1
+ar t pkg-split-part-missing-data.deb
+dpkg-split -I pkg-split-part-missing-data.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-split: error: unexpected end of file in reading data part member ar header in pkg-split-part-missing-data.deb
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-split
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-split.at:104"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:114:
+# Test duplicate debian-split member
+cp pkg-split-part.1of10.deb pkg-split-part-duplicate-magic.deb
+ar x pkg-split-part-duplicate-magic.deb debian-split
+ar ra debian-split pkg-split-part-duplicate-magic.deb debian-split debian-split
+ar t pkg-split-part-duplicate-magic.deb
+dpkg-split -I pkg-split-part-duplicate-magic.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:114"
+( $at_check_trace;
+# Test duplicate debian-split member
+cp pkg-split-part.1of10.deb pkg-split-part-duplicate-magic.deb
+ar x pkg-split-part-duplicate-magic.deb debian-split
+ar ra debian-split pkg-split-part-duplicate-magic.deb debian-split debian-split
+ar t pkg-split-part-duplicate-magic.deb
+dpkg-split -I pkg-split-part-duplicate-magic.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "dpkg-split: error: file 'pkg-split-part-duplicate-magic.deb' is corrupt - second member is not data member
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-split
+debian-split
+data.1
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/deb-split.at:114"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:127:
+# Test unknown extra member
+cp pkg-split-part.1of10.deb pkg-split-part-extra-member.deb
+echo \"some content\" >unknown
+ar q pkg-split-part-extra-member.deb unknown
+ar t pkg-split-part-extra-member.deb
+dpkg-split -I pkg-split-part-extra-member.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:127"
+( $at_check_trace;
+# Test unknown extra member
+cp pkg-split-part.1of10.deb pkg-split-part-extra-member.deb
+echo "some content" >unknown
+ar q pkg-split-part-extra-member.deb unknown
+ar t pkg-split-part-extra-member.deb
+dpkg-split -I pkg-split-part-extra-member.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "debian-split
+data.1
+unknown
+pkg-split-part-extra-member.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:127"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:152:
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.1of10.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:152"
+( $at_check_trace;
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.1of10.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "pkg-split-part.1of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 1/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 0 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:152"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:169:
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.2of10.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:169"
+( $at_check_trace;
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.2of10.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "pkg-split-part.2of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 2/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 214016 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:169"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:186:
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.9of10.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:186"
+( $at_check_trace;
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.9of10.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "pkg-split-part.9of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 9/10
+ Part length: $DEB_SPLIT_PART_LENGTH bytes
+ Part offset: 1712128 bytes
+ Part file size (used portion): $DEB_SPLIT_PART_SIZE bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:186"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:203:
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.10of10.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:203"
+( $at_check_trace;
+# Test getting information about the split parts (parsing verification)
+dpkg-split -I pkg-split-part.10of10.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "pkg-split-part.10of10.deb:
+ Part format version: 2.1
+ Part of package: pkg-split
+ ... version: 0.0-1
+ ... architecture: all
+ ... MD5 checksum: $DEB_SPLIT_MD5SUM
+ ... length: $DEB_SPLIT_LENGTH bytes
+ ... split every: $DEB_SPLIT_PART_LENGTH bytes
+ Part number: 10/10
+ Part length: $DEB_SPLIT_LAST_LENGTH bytes
+ Part offset: 1926144 bytes
+ Part file size (used portion): $DEB_SPLIT_LAST_SIZE bytes
+
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:203"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/deb-split.at:221:
+# Test joining the split parts back together
+dpkg-split -o pkg-joined.deb -j pkg-split-part.*.deb
+cmp pkg-split.deb pkg-joined.deb
+"
+at_fn_check_prepare_notrace 'an embedded newline' "deb-split.at:221"
+( $at_check_trace;
+# Test joining the split parts back together
+dpkg-split -o pkg-joined.deb -j pkg-split-part.*.deb
+cmp pkg-split.deb pkg-joined.deb
+
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "Putting package pkg-split together from 10 parts: 1 2 3 4 5 6 7 8 9 10 done
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/deb-split.at:221"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_7
+#AT_START_8
+at_fn_group_banner 8 'realpath.at:1' \
+ "dpkg-realpath options" " " 3
+at_xfail=no
+(
+ printf "%s\n" "8. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:4: dpkg-realpath --version"
+at_fn_check_prepare_trace "realpath.at:4"
+( $at_check_trace; dpkg-realpath --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:4"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:5: dpkg-realpath --help"
+at_fn_check_prepare_trace "realpath.at:5"
+( $at_check_trace; dpkg-realpath --help
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_8
+#AT_START_9
+at_fn_group_banner 9 'realpath.at:9' \
+ "dpkg-realpath path resolving" " " 3
+at_xfail=no
+(
+ printf "%s\n" "9. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+mkdir -p aa/bb/cc
+mkdir -p zz/yy/xx
+mkdir -p usr/bin
+: >aa/bb/cc/file
+ln -sfT aa/bb/cc/file zz/yy/xx/symlink-rel
+ln -sfT /aa/bb/cc/file zz/yy/xx/symlink-abs
+: >usr/bin/a-shell
+ln -sfT /usr/bin/a-shell usr/bin/sh
+
+tmpdir="$(pwd)"
+export DPKG_ROOT=
+
+# Relative paths
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:25: dpkg-realpath aa/bb/cc"
+at_fn_check_prepare_trace "realpath.at:25"
+( $at_check_trace; dpkg-realpath aa/bb/cc
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/aa/bb/cc
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:25"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:28: dpkg-realpath zz/yy/xx"
+at_fn_check_prepare_trace "realpath.at:28"
+( $at_check_trace; dpkg-realpath zz/yy/xx
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/zz/yy/xx
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:30: dpkg-realpath usr/bin"
+at_fn_check_prepare_trace "realpath.at:30"
+( $at_check_trace; dpkg-realpath usr/bin
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/usr/bin
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:30"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:32: dpkg-realpath aa/bb/cc/file"
+at_fn_check_prepare_trace "realpath.at:32"
+( $at_check_trace; dpkg-realpath aa/bb/cc/file
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:32"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:34: dpkg-realpath zz/yy/xx/symlink-rel"
+at_fn_check_prepare_trace "realpath.at:34"
+( $at_check_trace; dpkg-realpath zz/yy/xx/symlink-rel
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/zz/yy/xx/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:34"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:37: dpkg-realpath zz/yy/xx/symlink-abs"
+at_fn_check_prepare_trace "realpath.at:37"
+( $at_check_trace; dpkg-realpath zz/yy/xx/symlink-abs
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:37"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:39: dpkg-realpath usr/bin/a-shell"
+at_fn_check_prepare_trace "realpath.at:39"
+( $at_check_trace; dpkg-realpath usr/bin/a-shell
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:42: dpkg-realpath usr/bin/sh"
+at_fn_check_prepare_trace "realpath.at:42"
+( $at_check_trace; dpkg-realpath usr/bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:42"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+# Absolute paths
+cd /
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:47: dpkg-realpath \"\$tmpdir/aa/bb/cc\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/aa/bb/cc\"" "realpath.at:47"
+( $at_check_trace; dpkg-realpath "$tmpdir/aa/bb/cc"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/aa/bb/cc
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:47"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:49: dpkg-realpath \"\$tmpdir/zz/yy/xx\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/zz/yy/xx\"" "realpath.at:49"
+( $at_check_trace; dpkg-realpath "$tmpdir/zz/yy/xx"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/zz/yy/xx
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:51: dpkg-realpath \"\$tmpdir/usr/bin\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/usr/bin\"" "realpath.at:51"
+( $at_check_trace; dpkg-realpath "$tmpdir/usr/bin"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/usr/bin
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:53: dpkg-realpath \"\$tmpdir/aa/bb/cc/file\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/aa/bb/cc/file\"" "realpath.at:53"
+( $at_check_trace; dpkg-realpath "$tmpdir/aa/bb/cc/file"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:53"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:56: dpkg-realpath \"\$tmpdir/zz/yy/xx/symlink-rel\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/zz/yy/xx/symlink-rel\"" "realpath.at:56"
+( $at_check_trace; dpkg-realpath "$tmpdir/zz/yy/xx/symlink-rel"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/zz/yy/xx/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:56"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:59: dpkg-realpath \"\$tmpdir/zz/yy/xx/symlink-abs\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/zz/yy/xx/symlink-abs\"" "realpath.at:59"
+( $at_check_trace; dpkg-realpath "$tmpdir/zz/yy/xx/symlink-abs"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:61: dpkg-realpath \"\$tmpdir/usr/bin/a-shell\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/usr/bin/a-shell\"" "realpath.at:61"
+( $at_check_trace; dpkg-realpath "$tmpdir/usr/bin/a-shell"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "$tmpdir/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:64: dpkg-realpath \"\$tmpdir/usr/bin/sh\""
+at_fn_check_prepare_dynamic "dpkg-realpath \"$tmpdir/usr/bin/sh\"" "realpath.at:64"
+( $at_check_trace; dpkg-realpath "$tmpdir/usr/bin/sh"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+# Chrooted paths
+DPKG_ROOT="$tmpdir"
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:69: dpkg-realpath /aa/bb/cc"
+at_fn_check_prepare_trace "realpath.at:69"
+( $at_check_trace; dpkg-realpath /aa/bb/cc
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/aa/bb/cc
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:71: dpkg-realpath /zz/yy/xx"
+at_fn_check_prepare_trace "realpath.at:71"
+( $at_check_trace; dpkg-realpath /zz/yy/xx
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/zz/yy/xx
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:73: dpkg-realpath /usr/bin"
+at_fn_check_prepare_trace "realpath.at:73"
+( $at_check_trace; dpkg-realpath /usr/bin
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/usr/bin
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:73"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:75: dpkg-realpath /aa/bb/cc/file"
+at_fn_check_prepare_trace "realpath.at:75"
+( $at_check_trace; dpkg-realpath /aa/bb/cc/file
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:75"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:77: dpkg-realpath /zz/yy/xx/symlink-rel"
+at_fn_check_prepare_trace "realpath.at:77"
+( $at_check_trace; dpkg-realpath /zz/yy/xx/symlink-rel
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/zz/yy/xx/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:77"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:79: dpkg-realpath /zz/yy/xx/symlink-abs"
+at_fn_check_prepare_trace "realpath.at:79"
+( $at_check_trace; dpkg-realpath /zz/yy/xx/symlink-abs
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/aa/bb/cc/file
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:81: dpkg-realpath /usr/bin/a-shell"
+at_fn_check_prepare_trace "realpath.at:81"
+( $at_check_trace; dpkg-realpath /usr/bin/a-shell
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:81"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/realpath.at:83: dpkg-realpath /usr/bin/sh"
+at_fn_check_prepare_trace "realpath.at:83"
+( $at_check_trace; dpkg-realpath /usr/bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/usr/bin/a-shell
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/realpath.at:83"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_9
+#AT_START_10
+at_fn_group_banner 10 'divert.at:1' \
+ "dpkg-divert options" " " 4
+at_xfail=no
+(
+ printf "%s\n" "10. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst//testdir"
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:6: dpkg-divert --version"
+at_fn_check_prepare_trace "divert.at:6"
+( $at_check_trace; dpkg-divert --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:6"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:7: dpkg-divert --help"
+at_fn_check_prepare_trace "divert.at:7"
+( $at_check_trace; dpkg-divert --help
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:7"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:9: dpkg-divert --admindir"
+at_fn_check_prepare_trace "divert.at:9"
+( $at_check_trace; dpkg-divert --admindir
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:9"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:10: grep -qE '(takes a value|needs.*argument)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:10"
+( $at_check_trace; grep -qE '(takes a value|needs.*argument)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:10"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:12: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --jachsmitbju"
+at_fn_check_prepare_trace "divert.at:12"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --jachsmitbju
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:12"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:13: grep -q 'unknown option' stderr"
+at_fn_check_prepare_trace "divert.at:13"
+( $at_check_trace; grep -q 'unknown option' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:13"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:15: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add --remove"
+at_fn_check_prepare_trace "divert.at:15"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add --remove
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:15"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:16: grep -qE '(conflicting|two).*remove.*add.*' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:16"
+( $at_check_trace; grep -qE '(conflicting|two).*remove.*add.*' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:16"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:18: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert"
+at_fn_check_prepare_trace "divert.at:18"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:18"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:19: grep -qE '(takes a value|needs.*argument)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:19"
+( $at_check_trace; grep -qE '(takes a value|needs.*argument)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:19"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:21: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert foo"
+at_fn_check_prepare_trace "divert.at:21"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:21"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:22: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:22"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:22"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:24: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert \"/foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:24"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert "/foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:24"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:26: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:26"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:26"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:28: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package"
+at_fn_check_prepare_trace "divert.at:28"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:28"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:29: grep -qE '(takes a value|needs.*argument)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:29"
+( $at_check_trace; grep -qE '(takes a value|needs.*argument)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:29"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:31: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package \"foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:31"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package "foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:31"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:33: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:33"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:33"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:35: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add"
+at_fn_check_prepare_trace "divert.at:35"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:35"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:36: grep -q 'needs a single argument' stderr"
+at_fn_check_prepare_trace "divert.at:36"
+( $at_check_trace; grep -q 'needs a single argument' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:36"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:38: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add foo"
+at_fn_check_prepare_trace "divert.at:38"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:38"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:39: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:39"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:39"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:41: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add \"/foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:41"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add "/foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:41"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:43: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:43"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:43"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:45: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add \"/testdir\""
+at_fn_check_prepare_trace "divert.at:45"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add "/testdir"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:45"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:46: grep -qE 'director(y|ies)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:46"
+( $at_check_trace; grep -qE 'director(y|ies)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:46"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:48: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add --divert bar /foo/bar"
+at_fn_check_prepare_trace "divert.at:48"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --add --divert bar /foo/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:48"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:49: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:49"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:49"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:51: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove"
+at_fn_check_prepare_trace "divert.at:51"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:51"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:52: grep -q 'needs a single argument' stderr"
+at_fn_check_prepare_trace "divert.at:52"
+( $at_check_trace; grep -q 'needs a single argument' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:52"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:54: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove foo"
+at_fn_check_prepare_trace "divert.at:54"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:54"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:55: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:55"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:55"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:57: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove \"/foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:57"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --remove "/foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:57"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:59: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:59"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:59"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:61: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage"
+at_fn_check_prepare_trace "divert.at:61"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:61"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:62: grep -q 'needs a single argument' stderr"
+at_fn_check_prepare_trace "divert.at:62"
+( $at_check_trace; grep -q 'needs a single argument' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:62"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:64: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage foo"
+at_fn_check_prepare_trace "divert.at:64"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:64"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:65: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:65"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:65"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:67: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage \"/foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:67"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage "/foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:67"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:69: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:69"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:69"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:71: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename"
+at_fn_check_prepare_trace "divert.at:71"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:71"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:72: grep -q 'needs a single argument' stderr"
+at_fn_check_prepare_trace "divert.at:72"
+( $at_check_trace; grep -q 'needs a single argument' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:72"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:74: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename foo"
+at_fn_check_prepare_trace "divert.at:74"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:74"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:75: grep -q 'absolute' stderr"
+at_fn_check_prepare_trace "divert.at:75"
+( $at_check_trace; grep -q 'absolute' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:75"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:77: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename \"/foo
+bar\""
+at_fn_check_prepare_notrace 'an embedded newline' "divert.at:77"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename "/foo
+bar"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:77"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:79: grep -q 'newline' stderr"
+at_fn_check_prepare_trace "divert.at:79"
+( $at_check_trace; grep -q 'newline' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:79"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_10
+#AT_START_11
+at_fn_group_banner 11 'divert.at:83' \
+ "dpkg-divert query (empty db)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "11. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:88: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list"
+at_fn_check_prepare_trace "divert.at:88"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:88"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:89: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*'"
+at_fn_check_prepare_trace "divert.at:89"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:89"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:90: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list 'baz'"
+at_fn_check_prepare_trace "divert.at:90"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list 'baz'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:90"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_11
+#AT_START_12
+at_fn_group_banner 12 'divert.at:94' \
+ "dpkg-divert query (list)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "12. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ cat >dpkgdb/diversions <<'_ATEOF'
+/bin/sh
+/bin/sh.distrib
+dash
+/usr/share/man/man1/sh.1.gz
+/usr/share/man/man1/sh.distrib.1.gz
+dash
+/usr/bin/nm
+/usr/bin/nm.single
+binutils-multiarch
+_ATEOF
+
+
+
+
+
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:118: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list"
+at_fn_check_prepare_trace "divert.at:118"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /usr/bin/nm to /usr/bin/nm.single by binutils-multiarch
+diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:118"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:119: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*'"
+at_fn_check_prepare_trace "divert.at:119"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /usr/bin/nm to /usr/bin/nm.single by binutils-multiarch
+diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:119"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:120: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list ''"
+at_fn_check_prepare_trace "divert.at:120"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list ''
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:120"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:122: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '???????'"
+at_fn_check_prepare_trace "divert.at:122"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '???????'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:122"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:123: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*/sh'"
+at_fn_check_prepare_trace "divert.at:123"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '*/sh'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:123"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:124: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '/bin/*'"
+at_fn_check_prepare_trace "divert.at:124"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list '/bin/*'
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:124"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:125: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list binutils-multiarch"
+at_fn_check_prepare_trace "divert.at:125"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list binutils-multiarch
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /usr/bin/nm to /usr/bin/nm.single by binutils-multiarch
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:125"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:126: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /bin/sh"
+at_fn_check_prepare_trace "divert.at:126"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:126"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:127: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list -- /bin/sh"
+at_fn_check_prepare_trace "divert.at:127"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list -- /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:127"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:128: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /usr/bin/nm.single"
+at_fn_check_prepare_trace "divert.at:128"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /usr/bin/nm.single
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /usr/bin/nm to /usr/bin/nm.single by binutils-multiarch
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:128"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:129: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /bin/sh /usr/share/man/man1/sh.1.gz"
+at_fn_check_prepare_trace "divert.at:129"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list /bin/sh /usr/share/man/man1/sh.1.gz
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+diversion of /bin/sh to /bin/sh.distrib by dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:129"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_12
+#AT_START_13
+at_fn_group_banner 13 'divert.at:134' \
+ "dpkg-divert query (listpackage + truename)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "13. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ cat >dpkgdb/diversions <<'_ATEOF'
+/bin/sh
+/bin/sh.distrib
+dash
+/bin/true
+/bin/true.coreutils
+:
+_ATEOF
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:145: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/sh"
+at_fn_check_prepare_trace "divert.at:145"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "dash
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:145"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:147: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/true"
+at_fn_check_prepare_trace "divert.at:147"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/true
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "LOCAL
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:147"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:149: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/false"
+at_fn_check_prepare_trace "divert.at:149"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --listpackage /bin/false
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:149"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:151: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/sh"
+at_fn_check_prepare_trace "divert.at:151"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/bin/sh.distrib
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:151"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:153: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/sh.distrib"
+at_fn_check_prepare_trace "divert.at:153"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/sh.distrib
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/bin/sh.distrib
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:153"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:155: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/something"
+at_fn_check_prepare_trace "divert.at:155"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --truename /bin/something
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo >>"$at_stdout"; printf "%s\n" "/bin/something
+" | \
+ $at_diff - "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:155"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_13
+#AT_START_14
+at_fn_group_banner 14 'divert.at:160' \
+ "dpkg-divert add (local rename)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "14. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:170: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:170"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:170"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:171: grep -q \"Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib\" stdout"
+at_fn_check_prepare_trace "divert.at:171"
+( $at_check_trace; grep -q "Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib" stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:171"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:172: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:172"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:172"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:173: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:173"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:173"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:174: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:174"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:174"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_14
+#AT_START_15
+at_fn_group_banner 15 'divert.at:178' \
+ "dpkg-divert add (local no-rename)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "15. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:188: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:188"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:188"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:189: grep -q \"Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib\" stdout"
+at_fn_check_prepare_trace "divert.at:189"
+( $at_check_trace; grep -q "Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib" stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:189"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:190: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:190"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:190"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:191: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:191"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:191"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:192: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:192"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:192"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_15
+#AT_START_16
+at_fn_group_banner 16 'divert.at:196' \
+ "dpkg-divert add (rename quiet)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "16. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:206: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:206"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:206"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:207: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:207"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:207"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:208: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:208"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:208"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:209: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:209"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:209"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_16
+#AT_START_17
+at_fn_group_banner 17 'divert.at:213' \
+ "dpkg-divert add (test rename quiet)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "17. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:219: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --test /testdir/foo"
+at_fn_check_prepare_trace "divert.at:219"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --test /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:219"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:220: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:220"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:220"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:221: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:221"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:221"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:222: cat dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:222"
+( $at_check_trace; cat dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:222"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_17
+#AT_START_18
+at_fn_group_banner 18 'divert.at:226' \
+ "dpkg-divert add (rename missing quiet)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "18. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst//testdir"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:236: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:236"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:236"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:237: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:237"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:237"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:238: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:238"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:238"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:239: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:239"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:239"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_18
+#AT_START_19
+at_fn_group_banner 19 'divert.at:243' \
+ "dpkg-divert add (local rename quiet)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "19. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:253: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --local --rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:253"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --local --rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:253"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:254: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:254"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:254"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:255: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:255"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:255"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:256: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:256"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:256"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_19
+#AT_START_20
+at_fn_group_banner 20 'divert.at:260' \
+ "dpkg-divert add (package rename quiet)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "20. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+bash
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:269: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --package bash /testdir/foo"
+at_fn_check_prepare_trace "divert.at:269"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --package bash /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:269"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:270: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:270"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:270"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_20
+#AT_START_21
+at_fn_group_banner 21 'divert.at:274' \
+ "dpkg-divert add (rename self-link)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "21. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ ln "dpkginst//testdir/foo" "dpkginst//testdir/foo.distrib"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:285: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:285"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:285"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:286: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:286"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:286"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:287: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:287"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:287"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:288: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:288"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:288"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_21
+#AT_START_22
+at_fn_group_banner 22 'divert.at:292' \
+ "dpkg-divert add (rename other-file)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "22. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo.distrib')"
+ : >dpkginst//testdir/foo.distrib
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:299: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:299"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:299"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:300: grep -q 'error: rename involves overwriting' stderr"
+at_fn_check_prepare_trace "divert.at:300"
+( $at_check_trace; grep -q 'error: rename involves overwriting' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:300"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:301: cat dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:301"
+( $at_check_trace; cat dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:301"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_22
+#AT_START_23
+at_fn_group_banner 23 'divert.at:305' \
+ "dpkg-divert add (rename missing dir)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "23. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/zoo/foo
+/testdir/zoo/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:314: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/zoo/foo"
+at_fn_check_prepare_trace "divert.at:314"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/zoo/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:314"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:315: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:315"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:315"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_23
+#AT_START_24
+at_fn_group_banner 24 'divert.at:319' \
+ "dpkg-divert add (rename read-only dir)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "24. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "divert.at:322" >"$at_check_line_file"
+(test -n "$FAKEROOTKEY" || test "$(id -u)" = 0) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:322"
+
+
+ mkdir -p "dpkginst//testdir/rodir"
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/rodir/foo')"
+ : >dpkginst//testdir/rodir/foo
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/bar')"
+ : >dpkginst//testdir/bar
+
+
+ chmod 500 "dpkginst//testdir/rodir"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:330: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/rodir/foo"
+at_fn_check_prepare_trace "divert.at:330"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --add /testdir/rodir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:330"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:332: grep -q 'error: .* Permission denied' stderr"
+at_fn_check_prepare_trace "divert.at:332"
+( $at_check_trace; grep -q 'error: .* Permission denied' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:332"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:334: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --divert /testdir/rodir/bar --add /testdir/bar"
+at_fn_check_prepare_trace "divert.at:334"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --divert /testdir/rodir/bar --add /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:334"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:336: grep -q 'error: .* Permission denied' stderr"
+at_fn_check_prepare_trace "divert.at:336"
+( $at_check_trace; grep -q 'error: .* Permission denied' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:336"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:338: cat dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:338"
+( $at_check_trace; cat dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:338"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ chmod 755 "dpkginst//testdir/rodir"
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_24
+#AT_START_25
+at_fn_group_banner 25 'divert.at:343' \
+ "dpkg-divert add (rename no-access dir)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "25. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "divert.at:346" >"$at_check_line_file"
+(test -n "$FAKEROOTKEY" || test "$(id -u)" = 0) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:346"
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkginst//testdir/nadir"
+
+
+ chmod 000 "dpkginst//testdir/nadir"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:353: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/nadir/foo"
+at_fn_check_prepare_trace "divert.at:353"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/nadir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:353"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:354: grep -q 'error: .* Permission denied' stderr"
+at_fn_check_prepare_trace "divert.at:354"
+( $at_check_trace; grep -q 'error: .* Permission denied' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:354"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:356: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --divert /testdir/nadir/foo --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:356"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --divert /testdir/nadir/foo --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:356"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:358: grep -q 'error: .* Permission denied' stderr"
+at_fn_check_prepare_trace "divert.at:358"
+( $at_check_trace; grep -q 'error: .* Permission denied' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:358"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:360: cat dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:360"
+( $at_check_trace; cat dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:360"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+# On FreeBSD «rm -rf» cannot traverse a directory with mode 000.
+rmdir dpkginst/testdir/nadir
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_25
+#AT_START_26
+at_fn_group_banner 26 'divert.at:367' \
+ "dpkg-divert add second diversion" " " 4
+at_xfail=no
+(
+ printf "%s\n" "26. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst//testdir"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:373: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:373"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:373"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:374: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:374"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:374"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:376: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:376"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:376"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:377: grep -q 'Leaving' stdout"
+at_fn_check_prepare_trace "divert.at:377"
+( $at_check_trace; grep -q 'Leaving' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:377"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:379: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:379"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:379"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:380: grep -q 'Leaving' stdout"
+at_fn_check_prepare_trace "divert.at:380"
+( $at_check_trace; grep -q 'Leaving' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:380"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:382: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.bar /testdir/foo"
+at_fn_check_prepare_trace "divert.at:382"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.bar /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:382"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:384: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:384"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:384"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:386: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package foobar /testdir/foo"
+at_fn_check_prepare_trace "divert.at:386"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package foobar /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:386"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:387: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:387"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:387"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:389: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.distrib /testdir/bar"
+at_fn_check_prepare_trace "divert.at:389"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.distrib /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:389"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:391: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:391"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:391"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:393: dpkg-divert --admindir=dpkgdb --instdir=dpkginst /testdir/foo.distrib"
+at_fn_check_prepare_trace "divert.at:393"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst /testdir/foo.distrib
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:393"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:394: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:394"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:394"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:396: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo /testdir/bar"
+at_fn_check_prepare_trace "divert.at:396"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:396"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:397: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:397"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:397"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_26
+#AT_START_27
+at_fn_group_banner 27 'divert.at:401' \
+ "dpkg-divert add third diversion" " " 4
+at_xfail=no
+(
+ printf "%s\n" "27. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst//testdir"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:407: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:407"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:407"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:408: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:408"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:408"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:409: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/bar"
+at_fn_check_prepare_trace "divert.at:409"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:409"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:410: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:410"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:410"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:412: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:412"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:412"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:413: grep -q 'Leaving' stdout"
+at_fn_check_prepare_trace "divert.at:413"
+( $at_check_trace; grep -q 'Leaving' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:413"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:414: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --package foobar --add /testdir/bar"
+at_fn_check_prepare_trace "divert.at:414"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --package foobar --add /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:414"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:416: grep -q 'clashes' stderr"
+at_fn_check_prepare_trace "divert.at:416"
+( $at_check_trace; grep -q 'clashes' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:416"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_27
+#AT_START_28
+at_fn_group_banner 28 'divert.at:420' \
+ "dpkg-divert add (file owned by --package)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "28. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+# Only installed packages have their files list considered.
+
+ mkdir -p "dpkgdb"
+ cat >dpkgdb/status <<'_ATEOF'
+Package: coreutils
+Status: install ok installed
+Version: 0
+Architecture: i386
+Maintainer: dummy
+Description: dummy
+_ATEOF
+
+
+
+ mkdir -p "dpkgdb/info"
+ cat >dpkgdb/info/coreutils.list <<'_ATEOF'
+/testdir/foo
+_ATEOF
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+coreutils
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:440: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --package coreutils --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:440"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --package coreutils --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:440"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:441: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:441"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:441"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:442: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:442"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:442"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:443: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:443"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:443"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_28
+#AT_START_29
+at_fn_group_banner 29 'divert.at:447' \
+ "dpkg-divert remove (missing)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "29. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:452: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --remove /bin/sh"
+at_fn_check_prepare_trace "divert.at:452"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --remove /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:452"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:453: grep -q 'No diversion' stdout"
+at_fn_check_prepare_trace "divert.at:453"
+( $at_check_trace; grep -q 'No diversion' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:453"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:455: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --remove /bin/sh"
+at_fn_check_prepare_trace "divert.at:455"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --remove /bin/sh
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:455"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_29
+#AT_START_30
+at_fn_group_banner 30 'divert.at:459' \
+ "dpkg-divert remove (divert-to)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "30. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/bar
+/testdir/bar.distrib
+:
+/testdir/baz
+/testdir/baz.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:471: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:471"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:471"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:472: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/bar"
+at_fn_check_prepare_trace "divert.at:472"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:472"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:473: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/baz"
+at_fn_check_prepare_trace "divert.at:473"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/baz
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:473"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:475: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.my --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:475"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --divert /testdir/foo.my --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:475"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:477: grep -q 'mismatch on divert-to' stderr"
+at_fn_check_prepare_trace "divert.at:477"
+( $at_check_trace; grep -q 'mismatch on divert-to' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:477"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:479: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package baz --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:479"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package baz --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:479"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:480: grep -q 'mismatch on package' stderr"
+at_fn_check_prepare_trace "divert.at:480"
+( $at_check_trace; grep -q 'mismatch on package' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:480"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:482: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package baz --divert /testdir/foo.my --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:482"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --package baz --divert /testdir/foo.my --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:482"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:484: grep -qE 'mismatch on (package|divert-to)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:484"
+( $at_check_trace; grep -qE 'mismatch on (package|divert-to)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:484"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:486: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --divert /testdir/foo.distrib --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:486"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --divert /testdir/foo.distrib --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:486"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:488: grep -qE 'Removing .*/testdir/foo' stdout"
+at_fn_check_prepare_trace "divert.at:488"
+( $at_check_trace; grep -qE 'Removing .*/testdir/foo' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:488"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:490: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:490"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:490"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_30
+#AT_START_31
+at_fn_group_banner 31 'divert.at:494' \
+ "dpkg-divert remove (plain)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "31. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+/testdir/baz
+/testdir/baz.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:506: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:506"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:506"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:507: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/bar"
+at_fn_check_prepare_trace "divert.at:507"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:507"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:508: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/baz"
+at_fn_check_prepare_trace "divert.at:508"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --add /testdir/baz
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:508"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:510: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --remove /testdir/bar"
+at_fn_check_prepare_trace "divert.at:510"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --remove /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:510"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:511: grep -qE 'Removing .* /testdir/bar' stdout"
+at_fn_check_prepare_trace "divert.at:511"
+( $at_check_trace; grep -qE 'Removing .* /testdir/bar' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:511"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:513: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:513"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:513"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_31
+#AT_START_32
+at_fn_group_banner 32 'divert.at:517' \
+ "dpkg-divert remove (by-package)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "32. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/bar
+/testdir/bar.distrib
+:
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:529: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:529"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:529"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:530: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename /testdir/bar"
+at_fn_check_prepare_trace "divert.at:530"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename /testdir/bar
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:530"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:531: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --package bash /testdir/baz"
+at_fn_check_prepare_trace "divert.at:531"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --no-rename --package bash /testdir/baz
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:531"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:533: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --quiet --package bash --remove /testdir/baz"
+at_fn_check_prepare_trace "divert.at:533"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --no-rename --quiet --package bash --remove /testdir/baz
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:533"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:535: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:535"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:535"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_32
+#AT_START_33
+at_fn_group_banner 33 'divert.at:539' \
+ "dpkg-divert remove (test)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "33. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkginst/$(dirname '/testdir/foo')"
+ : >dpkginst//testdir/foo
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+cat >ref-diversions <<'_ATEOF'
+/testdir/foo
+/testdir/foo.distrib
+:
+_ATEOF
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:549: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo"
+at_fn_check_prepare_trace "divert.at:549"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:549"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:551: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --test --rename --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:551"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --test --rename --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:551"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:552: grep -q 'Removing .*/testdir/foo' stdout"
+at_fn_check_prepare_trace "divert.at:552"
+( $at_check_trace; grep -q 'Removing .*/testdir/foo' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:552"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:553: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:553"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:553"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:554: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:554"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:554"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:555: diff -u ref-diversions dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:555"
+( $at_check_trace; diff -u ref-diversions dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:555"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:557: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --remove /testdir/foo"
+at_fn_check_prepare_trace "divert.at:557"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --quiet --rename --remove /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:557"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:558: test -e \"dpkginst//testdir/foo\""
+at_fn_check_prepare_trace "divert.at:558"
+( $at_check_trace; test -e "dpkginst//testdir/foo"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:558"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/divert.at:559: test -e \"dpkginst//testdir/foo.distrib\""
+at_fn_check_prepare_trace "divert.at:559"
+( $at_check_trace; test -e "dpkginst//testdir/foo.distrib"
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 1 $at_status "$at_srcdir/divert.at:559"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:560: cat dpkgdb/diversions"
+at_fn_check_prepare_trace "divert.at:560"
+( $at_check_trace; cat dpkgdb/diversions
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:560"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_33
+#AT_START_34
+at_fn_group_banner 34 'divert.at:564' \
+ "dpkg-divert db (no-access)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "34. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "divert.at:567" >"$at_check_line_file"
+(test -n "$FAKEROOTKEY" || test "$(id -u)" = 0) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:567"
+
+# An inexistent diversions db file should not be considered a failure,
+# but a failure to open it should be.
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+ chmod 000 "dpkgdb/diversions"
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:574: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list"
+at_fn_check_prepare_trace "divert.at:574"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:574"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:575: grep -qE '(cannot|failed).*open' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:575"
+( $at_check_trace; grep -qE '(cannot|failed).*open' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:575"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ chmod 644 "dpkgdb/diversions"
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_34
+#AT_START_35
+at_fn_group_banner 35 'divert.at:580' \
+ "dpkg-divert db (truncated)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "35. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ cat >dpkgdb/diversions <<'_ATEOF'
+/bin/sh
+_ATEOF
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:586: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list"
+at_fn_check_prepare_trace "divert.at:586"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:586"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:587: grep -qE '(corrupt|unexpected end of file)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:587"
+( $at_check_trace; grep -qE '(corrupt|unexpected end of file)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:587"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ mkdir -p "dpkgdb"
+ cat >dpkgdb/diversions <<'_ATEOF'
+/bin/sh
+bash
+_ATEOF
+
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:593: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list"
+at_fn_check_prepare_trace "divert.at:593"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --list
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:593"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:594: grep -qE '(corrupt|unexpected end of file)' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:594"
+( $at_check_trace; grep -qE '(corrupt|unexpected end of file)' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:594"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_35
+#AT_START_36
+at_fn_group_banner 36 'divert.at:598' \
+ "dpkg-divert db (read-only dir)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "36. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "divert.at:601" >"$at_check_line_file"
+(test -n "$FAKEROOTKEY" || test "$(id -u)" = 0) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:601"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+
+ chmod 500 "dpkgdb/"
+
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:606: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:606"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:606"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:607: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:607"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:607"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:608: grep -q 'create.*new' stderr"
+at_fn_check_prepare_trace "divert.at:608"
+( $at_check_trace; grep -q 'create.*new' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:608"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+
+ chmod 755 "dpkgdb/"
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_36
+#AT_START_37
+at_fn_group_banner 37 'divert.at:613' \
+ "dpkg-divert db (disk full)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "37. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+printf "%s\n" "divert.at:616" >"$at_check_line_file"
+(test -n "$FAKEROOTKEY" || test "$(id -u)" = 0) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:616"
+printf "%s\n" "divert.at:617" >"$at_check_line_file"
+(! test -c /dev/full) \
+ && at_fn_check_skip 77 "$at_srcdir/divert.at:617"
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+ln -s /dev/full dpkgdb/diversions-new
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:622: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:622"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:622"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:623: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:623"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:623"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:624: grep -qE '(write|flush|close).*new' stderr"
+at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:624"
+( $at_check_trace; grep -qE '(write|flush|close).*new' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:624"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_37
+#AT_START_38
+at_fn_group_banner 38 'divert.at:628' \
+ "dpkg-divert db (pathname is dir)" " " 4
+at_xfail=no
+(
+ printf "%s\n" "38. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+
+ mkdir -p "dpkgdb"
+ : >dpkgdb/diversions
+
+rm -f dpkgdb/diversions-new
+mkdir dpkgdb/diversions-old
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:635: dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo"
+at_fn_check_prepare_trace "divert.at:635"
+( $at_check_trace; dpkg-divert --admindir=dpkgdb --instdir=dpkginst --rename --add /testdir/foo
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo stderr:; tee stderr <"$at_stderr"
+echo stdout:; tee stdout <"$at_stdout"
+at_fn_check_status 2 $at_status "$at_srcdir/divert.at:635"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:636: grep -q 'Adding' stdout"
+at_fn_check_prepare_trace "divert.at:636"
+( $at_check_trace; grep -q 'Adding' stdout
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:636"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+{ set +x
+printf "%s\n" "$at_srcdir/divert.at:637: grep -q 'remov.*old' stderr"
+at_fn_check_prepare_trace "divert.at:637"
+( $at_check_trace; grep -q 'remov.*old' stderr
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+at_fn_diff_devnull "$at_stderr" || at_failed=:
+at_fn_diff_devnull "$at_stdout" || at_failed=:
+at_fn_check_status 0 $at_status "$at_srcdir/divert.at:637"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_38
+#AT_START_39
+at_fn_group_banner 39 'chdir.at:5' \
+ "dpkg chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "39. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_39
+#AT_START_40
+at_fn_group_banner 40 'chdir.at:5' \
+ "dpkg chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "40. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_40
+#AT_START_41
+at_fn_group_banner 41 'chdir.at:5' \
+ "dpkg chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "41. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_41
+#AT_START_42
+at_fn_group_banner 42 'chdir.at:5' \
+ "dpkg chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "42. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_42
+#AT_START_43
+at_fn_group_banner 43 'chdir.at:5' \
+ "dpkg chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "43. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_43
+#AT_START_44
+at_fn_group_banner 44 'chdir.at:5' \
+ "dpkg-divert chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "44. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_44
+#AT_START_45
+at_fn_group_banner 45 'chdir.at:5' \
+ "dpkg-divert chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "45. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_45
+#AT_START_46
+at_fn_group_banner 46 'chdir.at:5' \
+ "dpkg-divert chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "46. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_46
+#AT_START_47
+at_fn_group_banner 47 'chdir.at:5' \
+ "dpkg-divert chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "47. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_47
+#AT_START_48
+at_fn_group_banner 48 'chdir.at:5' \
+ "dpkg-divert chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "48. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-divert --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_48
+#AT_START_49
+at_fn_group_banner 49 'chdir.at:5' \
+ "dpkg-statoverride chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "49. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:5"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_49
+#AT_START_50
+at_fn_group_banner 50 'chdir.at:5' \
+ "dpkg-statoverride chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "50. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_50
+#AT_START_51
+at_fn_group_banner 51 'chdir.at:5' \
+ "dpkg-statoverride chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "51. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_51
+#AT_START_52
+at_fn_group_banner 52 'chdir.at:5' \
+ "dpkg-statoverride chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "52. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_52
+#AT_START_53
+at_fn_group_banner 53 'chdir.at:5' \
+ "dpkg-statoverride chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "53. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --instdir=/instdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --root=/rootdir_opt --admindir=/admindir_opt --instdir=/instdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/instdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:5: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:5"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-statoverride --version --admindir=/admindir_opt --instdir=/instdir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:5"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_53
+#AT_START_54
+at_fn_group_banner 54 'chdir.at:329' \
+ "dpkg-split chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "54. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_54
+#AT_START_55
+at_fn_group_banner 55 'chdir.at:329' \
+ "dpkg-split chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "55. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-split --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-split --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_55
+#AT_START_56
+at_fn_group_banner 56 'chdir.at:329' \
+ "dpkg-split chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "56. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_56
+#AT_START_57
+at_fn_group_banner 57 'chdir.at:329' \
+ "dpkg-split chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "57. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_57
+#AT_START_58
+at_fn_group_banner 58 'chdir.at:329' \
+ "dpkg-split chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "58. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-split --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_58
+#AT_START_59
+at_fn_group_banner 59 'chdir.at:329' \
+ "dpkg-query chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "59. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_59
+#AT_START_60
+at_fn_group_banner 60 'chdir.at:329' \
+ "dpkg-query chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "60. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-query --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-query --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_60
+#AT_START_61
+at_fn_group_banner 61 'chdir.at:329' \
+ "dpkg-query chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "61. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_61
+#AT_START_62
+at_fn_group_banner 62 'chdir.at:329' \
+ "dpkg-query chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "62. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_62
+#AT_START_63
+at_fn_group_banner 63 'chdir.at:329' \
+ "dpkg-query chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "63. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-query --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_63
+#AT_START_64
+at_fn_group_banner 64 'chdir.at:329' \
+ "dpkg-trigger chdir opts" " " 5
+at_xfail=no
+(
+ printf "%s\n" "64. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_trace "chdir.at:329"
+( $at_check_trace; DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_64
+#AT_START_65
+at_fn_group_banner 65 'chdir.at:329' \
+ "dpkg-trigger chdir env" " " 5
+at_xfail=no
+(
+ printf "%s\n" "65. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/rootdir_env$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_env
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_65
+#AT_START_66
+at_fn_group_banner 66 'chdir.at:329' \
+ "dpkg-trigger chdir env+opt admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "66. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=$DEFAULT_ROOTDIR admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_66
+#AT_START_67
+at_fn_group_banner 67 'chdir.at:329' \
+ "dpkg-trigger chdir env+opt root" " " 5
+at_xfail=no
+(
+ printf "%s\n" "67. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_67
+#AT_START_68
+at_fn_group_banner 68 'chdir.at:329' \
+ "dpkg-trigger chdir env+opt root+admindir" " " 5
+at_xfail=no
+(
+ printf "%s\n" "68. $at_setup_line: testing $at_desc ..."
+ $at_traceon
+
+
+
+ DPKG_ROOT=
+ DPKG_ADMINDIR=
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_env admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --root=/rootdir_opt --admindir=/admindir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/admindir_opt
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+ { set +x
+printf "%s\n" "$at_srcdir/chdir.at:329: DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \\
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt"
+at_fn_check_prepare_notrace 'an embedded newline' "chdir.at:329"
+( $at_check_trace; DPKG_ROOT=/rootdir_env DPKG_ADMINDIR=/admindir_env \
+ DPKG_DEBUG=1 dpkg-trigger --version --admindir=/admindir_opt --root=/rootdir_opt
+) >>"$at_stdout" 2>>"$at_stderr" 5>&-
+at_status=$? at_failed=false
+$at_check_filter
+echo >>"$at_stderr"; printf "%s\n" "D000001: root=/rootdir_opt admindir=/rootdir_opt$DEFAULT_ADMINDIR
+" | \
+ $at_diff - "$at_stderr" || at_failed=:
+echo stdout:; cat "$at_stdout"
+at_fn_check_status 0 $at_status "$at_srcdir/chdir.at:329"
+$at_failed && at_fn_log_failure
+$at_traceon; }
+
+
+ set +x
+ $at_times_p && times >"$at_times_file"
+) 5>&1 2>&1 7>&- | eval $at_tee_pipe
+read at_status <"$at_status_file"
+#AT_STOP_68
diff --git a/src/at/testsuite.at b/src/at/testsuite.at
new file mode 100644
index 0000000..86e2d37
--- /dev/null
+++ b/src/at/testsuite.at
@@ -0,0 +1,24 @@
+AT_INIT([dpkg tools functional test suite])
+AT_COLOR_TESTS
+
+AT_TESTED([dpkg-deb])
+AT_BANNER([Binary .deb packages])
+m4_include([deb-format.at])
+m4_include([deb-content.at])
+m4_include([deb-fields.at])
+
+AT_TESTED([dpkg-split])
+AT_BANNER([Split .deb packages])
+m4_include([deb-split.at])
+
+AT_TESTED([dpkg-realpath])
+AT_BANNER([Resolve pathnames])
+m4_include([realpath.at])
+
+AT_TESTED([dpkg-divert])
+AT_BANNER([Diversions])
+m4_include([divert.at])
+
+AT_TESTED([dpkg])
+AT_BANNER([Change directory options])
+m4_include([chdir.at])
diff --git a/src/common/actions.h b/src/common/actions.h
new file mode 100644
index 0000000..a78f329
--- /dev/null
+++ b/src/common/actions.h
@@ -0,0 +1,78 @@
+/*
+ * dpkg - main program for package management
+ * actions.h - command action definition list
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2016 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 DPKG_ACTIONS_H
+#define DPKG_ACTIONS_H
+
+enum action {
+ act_unset,
+
+ act_unpack,
+ act_configure,
+ act_install,
+ act_triggers,
+ act_remove,
+ act_purge,
+ act_verify,
+ act_commandfd,
+
+ act_status,
+ act_listpackages,
+ act_listfiles,
+ act_searchfiles,
+ act_controlpath,
+ act_controllist,
+ act_controlshow,
+
+ act_cmpversions,
+
+ act_arch_add,
+ act_arch_remove,
+ act_printarch,
+ act_printforeignarches,
+
+ act_assert_feature,
+
+ act_validate_pkgname,
+ act_validate_trigname,
+ act_validate_archname,
+ act_validate_version,
+
+ act_audit,
+ act_unpackchk,
+ act_predeppackage,
+
+ act_getselections,
+ act_setselections,
+ act_clearselections,
+
+ act_avail,
+ act_printavail,
+ act_avclear,
+ act_avreplace,
+ act_avmerge,
+ act_forgetold,
+
+ act_help,
+ act_version,
+};
+
+#endif /* DPKG_ACTIONS_H */
diff --git a/src/common/force.c b/src/common/force.c
new file mode 100644
index 0000000..2e1fd78
--- /dev/null
+++ b/src/common/force.c
@@ -0,0 +1,404 @@
+/*
+ * dpkg - main program for package management
+ * force.c - force operation support
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2019 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 <errno.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/options.h>
+
+#include "force.h"
+
+static int force_mask;
+static int force_flags;
+
+enum forcetype {
+ FORCETYPE_DISABLED,
+ FORCETYPE_ENABLED,
+ FORCETYPE_DAMAGE,
+};
+
+static const char *
+forcetype_str(enum forcetype type)
+{
+ switch (type) {
+ case FORCETYPE_DISABLED:
+ return " ";
+ case FORCETYPE_ENABLED:
+ return "[*]";
+ case FORCETYPE_DAMAGE:
+ return "[!]";
+ default:
+ internerr("unknown force type '%d'", type);
+ }
+}
+
+static const struct forceinfo {
+ const char *name;
+ int flag;
+ char type;
+ const char *desc;
+} forceinfos[] = {
+ {
+ "all",
+ FORCE_ALL,
+ FORCETYPE_DAMAGE,
+ N_("Set all force options"),
+ }, {
+ "security-mac",
+ FORCE_SECURITY_MAC,
+ FORCETYPE_ENABLED,
+ N_("Use MAC based security if available"),
+ }, {
+ "downgrade",
+ FORCE_DOWNGRADE,
+ FORCETYPE_ENABLED,
+ N_("Replace a package with a lower version"),
+ }, {
+ "configure-any",
+ FORCE_CONFIGURE_ANY,
+ FORCETYPE_DISABLED,
+ N_("Configure any package which may help this one"),
+ }, {
+ "hold",
+ FORCE_HOLD,
+ FORCETYPE_DISABLED,
+ N_("Install or remove incidental packages even when on hold"),
+ }, {
+ "not-root",
+ FORCE_NON_ROOT,
+ FORCETYPE_DISABLED,
+ N_("Try to (de)install things even when not root"),
+ }, {
+ "bad-path",
+ FORCE_BAD_PATH,
+ FORCETYPE_DISABLED,
+ N_("PATH is missing important programs, problems likely"),
+ }, {
+ "bad-verify",
+ FORCE_BAD_VERIFY,
+ FORCETYPE_DISABLED,
+ N_("Install a package even if it fails authenticity check"),
+ }, {
+ "bad-version",
+ FORCE_BAD_VERSION,
+ FORCETYPE_DISABLED,
+ N_("Process even packages with wrong versions"),
+ }, {
+ "statoverride-add",
+ FORCE_STATOVERRIDE_ADD,
+ FORCETYPE_DISABLED,
+ N_("Overwrite an existing stat override when adding it"),
+ }, {
+ "statoverride-remove",
+ FORCE_STATOVERRIDE_DEL,
+ FORCETYPE_DISABLED,
+ N_("Ignore a missing stat override when removing it"),
+ }, {
+ "overwrite",
+ FORCE_OVERWRITE,
+ FORCETYPE_DISABLED,
+ N_("Overwrite a file from one package with another"),
+ }, {
+ "overwrite-diverted",
+ FORCE_OVERWRITE_DIVERTED,
+ FORCETYPE_DISABLED,
+ N_("Overwrite a diverted file with an undiverted version"),
+ }, {
+ "overwrite-dir",
+ FORCE_OVERWRITE_DIR,
+ FORCETYPE_DAMAGE,
+ N_("Overwrite one package's directory with another's file"),
+ }, {
+ "unsafe-io",
+ FORCE_UNSAFE_IO,
+ FORCETYPE_DAMAGE,
+ N_("Do not perform safe I/O operations when unpacking"),
+ }, {
+ "script-chrootless",
+ FORCE_SCRIPT_CHROOTLESS,
+ FORCETYPE_DAMAGE,
+ N_("Do not chroot into maintainer script environment"),
+ }, {
+ "confnew",
+ FORCE_CONFF_NEW,
+ FORCETYPE_DAMAGE,
+ N_("Always use the new config files, don't prompt"),
+ }, {
+ "confold",
+ FORCE_CONFF_OLD,
+ FORCETYPE_DAMAGE,
+ N_("Always use the old config files, don't prompt"),
+ }, {
+ "confdef",
+ FORCE_CONFF_DEF,
+ FORCETYPE_DAMAGE,
+ N_("Use the default option for new config files if one\n"
+ "is available, don't prompt. If no default can be found,\n"
+ "you will be prompted unless one of the confold or\n"
+ "confnew options is also given"),
+ }, {
+ "confmiss",
+ FORCE_CONFF_MISS,
+ FORCETYPE_DAMAGE,
+ N_("Always install missing config files"),
+ }, {
+ "confask",
+ FORCE_CONFF_ASK,
+ FORCETYPE_DAMAGE,
+ N_("Offer to replace config files with no new versions"),
+ }, {
+ "architecture",
+ FORCE_ARCHITECTURE,
+ FORCETYPE_DAMAGE,
+ N_("Process even packages with wrong or no architecture"),
+ }, {
+ "breaks",
+ FORCE_BREAKS,
+ FORCETYPE_DAMAGE,
+ N_("Install even if it would break another package"),
+ }, {
+ "conflicts",
+ FORCE_CONFLICTS,
+ FORCETYPE_DAMAGE,
+ N_("Allow installation of conflicting packages"),
+ }, {
+ "depends",
+ FORCE_DEPENDS,
+ FORCETYPE_DAMAGE,
+ N_("Turn all dependency problems into warnings"),
+ }, {
+ "depends-version",
+ FORCE_DEPENDS_VERSION,
+ FORCETYPE_DAMAGE,
+ N_("Turn dependency version problems into warnings"),
+ }, {
+ "remove-reinstreq",
+ FORCE_REMOVE_REINSTREQ,
+ FORCETYPE_DAMAGE,
+ N_("Remove packages which require installation"),
+ }, {
+ "remove-protected",
+ FORCE_REMOVE_PROTECTED,
+ FORCETYPE_DAMAGE,
+ N_("Remove a protected package"),
+ }, {
+ "remove-essential",
+ FORCE_REMOVE_ESSENTIAL,
+ FORCETYPE_DAMAGE,
+ N_("Remove an essential package"),
+ }, {
+ NULL
+ }
+};
+
+bool
+in_force(int flags)
+{
+ return (flags & force_flags) == flags;
+}
+
+void
+set_force(int flags)
+{
+ force_flags |= flags;
+}
+
+void
+reset_force(int flags)
+{
+ force_flags &= ~flags;
+}
+
+char *
+get_force_string(void)
+{
+ const struct forceinfo *fip;
+ struct varbuf vb = VARBUF_INIT;
+
+ for (fip = forceinfos; fip->name; fip++) {
+ if ((enum force_flags)fip->flag == FORCE_ALL ||
+ (fip->flag & force_mask) != fip->flag ||
+ !in_force(fip->flag))
+ continue;
+
+ if (vb.used)
+ varbuf_add_char(&vb, ',');
+ varbuf_add_str(&vb, fip->name);
+ }
+ varbuf_end_str(&vb);
+
+ return varbuf_detach(&vb);
+}
+
+static inline void
+print_forceinfo_line(int type, const char *name, const char *desc)
+{
+ printf(" %s %-18s %s\n", forcetype_str(type), name, desc);
+}
+
+static void
+print_forceinfo(const struct forceinfo *fi)
+{
+ char *desc, *line;
+
+ desc = m_strdup(gettext(fi->desc));
+
+ line = strtok(desc, "\n");
+ print_forceinfo_line(fi->type, fi->name, line);
+ while ((line = strtok(NULL, "\n")))
+ print_forceinfo_line(FORCETYPE_DISABLED, "", line);
+
+ free(desc);
+}
+
+void
+parse_force(const char *value, bool set)
+{
+ const char *comma;
+ size_t l;
+ const struct forceinfo *fip;
+
+ if (strcmp(value, "help") == 0) {
+ char *force_string = get_force_string();
+
+ printf(_(
+"%s forcing options - control behaviour when problems found:\n"
+" warn but continue: --force-<thing>,<thing>,...\n"
+" stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n"
+" Forcing things:\n"), dpkg_get_progname());
+
+ for (fip = forceinfos; fip->name; fip++)
+ if ((enum force_flags)fip->flag == FORCE_ALL ||
+ (fip->flag & force_mask) == fip->flag)
+ print_forceinfo(fip);
+
+ printf(_(
+"\n"
+"WARNING - use of options marked [!] can seriously damage your installation.\n"
+"Forcing options marked [*] are enabled by default.\n"));
+ m_output(stdout, _("<standard output>"));
+
+ printf(_(
+"\n"
+"Currently enabled options:\n"
+" %s\n"), force_string);
+
+ free(force_string);
+
+ exit(0);
+ }
+
+ for (;;) {
+ comma = strchrnul(value, ',');
+ l = (size_t)(comma - value);
+ for (fip = forceinfos; fip->name; fip++)
+ if (strncmp(fip->name, value, l) == 0 &&
+ strlen(fip->name) == l)
+ break;
+
+ if (!fip->name) {
+ badusage(_("unknown force/refuse option '%.*s'"),
+ (int)min(l, 250), value);
+ } else if (fip->flag) {
+ if (set)
+ set_force(fip->flag);
+ else
+ reset_force(fip->flag);
+ } else {
+ warning(_("obsolete force/refuse option '%s'"),
+ fip->name);
+ }
+
+ if (*comma == '\0')
+ break;
+ value = ++comma;
+ }
+}
+
+void
+set_force_default(int mask)
+{
+ const char *force_env;
+ const struct forceinfo *fip;
+
+ force_mask = mask;
+
+ /* If we get passed force options from the environment, do not
+ * initialize from the built-in defaults. */
+ force_env = getenv("DPKG_FORCE");
+ if (force_env != NULL) {
+ if (force_env[0] != '\0')
+ parse_force(force_env, 1);
+ return;
+ }
+
+ for (fip = forceinfos; fip->name; fip++)
+ if (fip->type == FORCETYPE_ENABLED)
+ set_force(fip->flag);
+}
+
+void
+set_force_option(const struct cmdinfo *cip, const char *value)
+{
+ bool set = cip->arg_int;
+
+ parse_force(value, set);
+}
+
+void
+reset_force_option(const struct cmdinfo *cip, const char *value)
+{
+ reset_force(cip->arg_int);
+}
+
+void
+forcibleerr(int forceflag, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (in_force(forceflag)) {
+ warning(_("overriding problem because --force enabled:"));
+ warningv(fmt, args);
+ } else {
+ ohshitv(fmt, args);
+ }
+ va_end(args);
+}
+
+int
+forcible_nonroot_error(int rc)
+{
+ if (in_force(FORCE_NON_ROOT) && errno == EPERM)
+ return 0;
+ return rc;
+}
diff --git a/src/common/force.h b/src/common/force.h
new file mode 100644
index 0000000..25a42fc
--- /dev/null
+++ b/src/common/force.h
@@ -0,0 +1,85 @@
+/*
+ * dpkg - main program for package management
+ * force.h - forced operation support
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2019 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 DPKG_FORCE_H
+#define DPKG_FORCE_H
+
+#include <dpkg/dpkg.h>
+#include <dpkg/options.h>
+
+enum force_flags {
+ FORCE_ARCHITECTURE = DPKG_BIT(0),
+ FORCE_BAD_PATH = DPKG_BIT(1),
+ FORCE_BAD_VERIFY = DPKG_BIT(2),
+ FORCE_BAD_VERSION = DPKG_BIT(3),
+ FORCE_BREAKS = DPKG_BIT(4),
+ FORCE_CONFF_ASK = DPKG_BIT(5),
+ FORCE_CONFF_DEF = DPKG_BIT(6),
+ FORCE_CONFF_MISS = DPKG_BIT(7),
+ FORCE_CONFF_NEW = DPKG_BIT(8),
+ FORCE_CONFF_OLD = DPKG_BIT(9),
+ FORCE_CONFIGURE_ANY = DPKG_BIT(10),
+ FORCE_CONFLICTS = DPKG_BIT(11),
+ FORCE_DEPENDS = DPKG_BIT(12),
+ FORCE_DEPENDS_VERSION = DPKG_BIT(13),
+ FORCE_DOWNGRADE = DPKG_BIT(14),
+ FORCE_HOLD = DPKG_BIT(15),
+ FORCE_NON_ROOT = DPKG_BIT(16),
+ FORCE_OVERWRITE = DPKG_BIT(17),
+ FORCE_OVERWRITE_DIR = DPKG_BIT(18),
+ FORCE_OVERWRITE_DIVERTED = DPKG_BIT(19),
+ FORCE_REMOVE_ESSENTIAL = DPKG_BIT(20),
+ FORCE_REMOVE_REINSTREQ = DPKG_BIT(21),
+ FORCE_SCRIPT_CHROOTLESS = DPKG_BIT(22),
+ FORCE_UNSAFE_IO = DPKG_BIT(23),
+ FORCE_STATOVERRIDE_ADD = DPKG_BIT(24),
+ FORCE_STATOVERRIDE_DEL = DPKG_BIT(25),
+ FORCE_SECURITY_MAC = DPKG_BIT(26),
+ FORCE_REMOVE_PROTECTED = DPKG_BIT(27),
+ FORCE_ALL = 0xffffffff,
+};
+
+bool
+in_force(int flags);
+void
+set_force(int flags);
+void
+reset_force(int flags);
+
+char *
+get_force_string(void);
+
+void
+parse_force(const char *value, bool set);
+
+void
+set_force_default(int mask);
+void
+set_force_option(const struct cmdinfo *cip, const char *value);
+void
+reset_force_option(const struct cmdinfo *cip, const char *value);
+
+void
+forcibleerr(int forceflag, const char *format, ...) DPKG_ATTR_PRINTF(2);
+int
+forcible_nonroot_error(int rc);
+
+#endif /* DPKG_FORCE_H */
diff --git a/src/common/security-mac.h b/src/common/security-mac.h
new file mode 100644
index 0000000..637c6f7
--- /dev/null
+++ b/src/common/security-mac.h
@@ -0,0 +1,30 @@
+/*
+ * dpkg - main program for package management
+ * security-mac.h - MAC-based security support
+ *
+ * Copyright © 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/>.
+ */
+
+#ifndef DPKG_SECURITY_MAC_H
+#define DPKG_SECURITY_MAC_H
+
+#include <sys/stat.h>
+
+void dpkg_selabel_load(void);
+void dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode);
+void dpkg_selabel_close(void);
+
+#endif /* DPKG_SECURITY_MAC_H */
diff --git a/src/common/selinux.c b/src/common/selinux.c
new file mode 100644
index 0000000..b5d29d8
--- /dev/null
+++ b/src/common/selinux.c
@@ -0,0 +1,156 @@
+/*
+ * dpkg - main program for package management
+ * selinux.c - SELinux support
+ *
+ * Copyright © 2007-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 <errno.h>
+#include <unistd.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+
+#ifdef WITH_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/avc.h>
+#include <selinux/label.h>
+#endif
+
+#include "force.h"
+#include "security-mac.h"
+
+#ifdef WITH_LIBSELINUX
+static struct selabel_handle *sehandle;
+#endif
+
+#ifdef WITH_LIBSELINUX
+static int DPKG_ATTR_PRINTF(2)
+log_callback(int type, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ switch (type) {
+ case SELINUX_ERROR:
+ case SELINUX_WARNING:
+ case SELINUX_AVC:
+ break;
+ default:
+ return 0;
+ }
+
+ va_start(ap, fmt);
+ m_vasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ warning("selinux: %s", msg);
+ free(msg);
+
+ return 0;
+}
+#endif
+
+void
+dpkg_selabel_load(void)
+{
+#ifdef WITH_LIBSELINUX
+ static int selinux_enabled = -1;
+
+ if (selinux_enabled < 0) {
+ int rc;
+
+ /* Set selinux_enabled if it is not already set (singleton). */
+ selinux_enabled = (in_force(FORCE_SECURITY_MAC) &&
+ is_selinux_enabled() > 0);
+ if (!selinux_enabled)
+ return;
+
+ /* Open the SELinux status notification channel, with fallback
+ * enabled for older kernels. */
+ rc = selinux_status_open(1);
+ if (rc < 0)
+ ohshit(_("cannot open security status notification channel"));
+
+ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) {
+ .func_log = log_callback,
+ });
+ } else if (selinux_enabled && selinux_status_updated()) {
+ /* The SELinux policy got updated in the kernel, usually after
+ * upgrading the package shipping it, we need to reload. */
+ selabel_close(sehandle);
+ } else {
+ /* SELinux is either disabled or it does not need a reload. */
+ return;
+ }
+
+ sehandle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
+ if (sehandle == NULL && security_getenforce() == 1)
+ ohshite(_("cannot get security labeling handle"));
+#endif
+}
+
+void
+dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode)
+{
+#ifdef WITH_LIBSELINUX
+ char *scontext = NULL;
+ int ret;
+
+ /* If SELinux is not enabled just do nothing. */
+ if (sehandle == NULL)
+ return;
+
+ /*
+ * We use the _raw function variants here so that no translation
+ * happens from computer to human readable forms, to avoid issues
+ * when mcstransd has disappeared during the unpack process.
+ */
+
+ /* Do nothing if we can't figure out what the context is, or if it has
+ * no context; in which case the default context shall be applied. */
+ ret = selabel_lookup_raw(sehandle, &scontext, matchpath, mode & S_IFMT);
+ if (ret == -1 || (ret == 0 && scontext == NULL))
+ return;
+
+ ret = lsetfilecon_raw(path, scontext);
+ if (ret < 0 && errno != ENOTSUP)
+ ohshite(_("cannot set security context for file object '%s'"),
+ path);
+
+ freecon(scontext);
+#endif /* WITH_LIBSELINUX */
+}
+
+void
+dpkg_selabel_close(void)
+{
+#ifdef WITH_LIBSELINUX
+ if (sehandle == NULL)
+ return;
+
+ selinux_status_close();
+ selabel_close(sehandle);
+ sehandle = NULL;
+#endif
+}
diff --git a/src/deb/build.c b/src/deb/build.c
new file mode 100644
index 0000000..5c74ff3
--- /dev/null
+++ b/src/deb/build.c
@@ -0,0 +1,730 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * build.c - building archives
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
+ * Copyright © 2007-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 <inttypes.h>
+#include <string.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdint.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/path.h>
+#include <dpkg/treewalk.h>
+#include <dpkg/varbuf.h>
+#include <dpkg/fdio.h>
+#include <dpkg/buffer.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/compress.h>
+#include <dpkg/ar.h>
+#include <dpkg/options.h>
+
+#include "dpkg-deb.h"
+
+static void
+control_treewalk_feed(const char *dir, int fd_out)
+{
+ struct treeroot *tree;
+ struct treenode *node;
+
+ tree = treewalk_open(dir, TREEWALK_NONE, NULL);
+ for (node = treewalk_node(tree); node; node = treewalk_next(tree)) {
+ char *nodename;
+
+ nodename = str_fmt("./%s", treenode_get_virtname(node));
+ if (fd_write(fd_out, nodename, strlen(nodename) + 1) < 0)
+ ohshite(_("failed to write filename to tar pipe (%s)"),
+ _("control member"));
+ free(nodename);
+ }
+ treewalk_close(tree);
+}
+
+/**
+ * Simple structure to store information about a file.
+ */
+struct file_info {
+ struct file_info *next;
+ char *fn;
+};
+
+static struct file_info *
+file_info_new(const char *filename)
+{
+ struct file_info *fi;
+
+ fi = m_malloc(sizeof(*fi));
+ fi->fn = m_strdup(filename);
+ fi->next = NULL;
+
+ return fi;
+}
+
+static void
+file_info_free(struct file_info *fi)
+{
+ free(fi->fn);
+ free(fi);
+}
+
+static struct file_info *
+file_info_find_name(struct file_info *list, const char *filename)
+{
+ struct file_info *node;
+
+ for (node = list; node; node = node->next)
+ if (strcmp(node->fn, filename) == 0)
+ return node;
+
+ return NULL;
+}
+
+/**
+ * Add a new file_info struct to a single linked list of file_info structs.
+ *
+ * We perform a slight optimization to work around a ‘feature’ in tar: tar
+ * always recurses into subdirectories if you list a subdirectory. So if an
+ * entry is added and the previous entry in the list is its subdirectory we
+ * remove the subdirectory.
+ *
+ * After a file_info struct is added to a list it may no longer be freed, we
+ * assume full responsibility for its memory.
+ */
+static void
+file_info_list_append(struct file_info **head, struct file_info **tail,
+ struct file_info *fi)
+{
+ if (*head == NULL)
+ *head = *tail = fi;
+ else
+ *tail = (*tail)->next =fi;
+}
+
+/**
+ * Free the memory for all entries in a list of file_info structs.
+ */
+static void
+file_info_list_free(struct file_info *fi)
+{
+ while (fi) {
+ struct file_info *fl;
+
+ fl=fi; fi=fi->next;
+ file_info_free(fl);
+ }
+}
+
+static void
+file_treewalk_feed(const char *dir, int fd_out)
+{
+ struct treeroot *tree;
+ struct treenode *node;
+ struct file_info *fi;
+ struct file_info *symlist = NULL;
+ struct file_info *symlist_end = NULL;
+
+ tree = treewalk_open(dir, TREEWALK_NONE, NULL);
+ for (node = treewalk_node(tree); node ; node = treewalk_next(tree)) {
+ const char *virtname = treenode_get_virtname(node);
+ char *nodename;
+
+ if (strncmp(virtname, BUILDCONTROLDIR, strlen(BUILDCONTROLDIR)) == 0)
+ continue;
+
+ nodename = str_fmt("./%s", virtname);
+
+ if (!nocheckflag && strchr(nodename, '\n'))
+ ohshit(_("newline not allowed in pathname '%s'"), nodename);
+
+ /* We need to reorder the files so we can make sure that symlinks
+ * will not appear before their target. */
+ if (S_ISLNK(treenode_get_mode(node))) {
+ fi = file_info_new(nodename);
+ file_info_list_append(&symlist, &symlist_end, fi);
+ } else {
+ if (fd_write(fd_out, nodename, strlen(nodename) + 1) < 0)
+ ohshite(_("failed to write filename to tar pipe (%s)"),
+ _("data member"));
+ }
+
+ free(nodename);
+ }
+ treewalk_close(tree);
+
+ for (fi = symlist; fi; fi = fi->next)
+ if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0)
+ ohshite(_("failed to write filename to tar pipe (%s)"), _("data member"));
+
+ file_info_list_free(symlist);
+}
+
+static const char *const maintainerscripts[] = {
+ PREINSTFILE,
+ POSTINSTFILE,
+ PRERMFILE,
+ POSTRMFILE,
+ MAINTSCRIPT_FILE_CONFIG,
+ NULL,
+};
+
+/**
+ * Check control directory and file permissions.
+ */
+static void
+check_file_perms(const char *ctrldir)
+{
+ struct varbuf path = VARBUF_INIT;
+ const char *const *mscriptp;
+ struct stat mscriptstab;
+
+ varbuf_printf(&path, "%s/", ctrldir);
+ if (lstat(path.buf, &mscriptstab))
+ ohshite(_("unable to stat control directory"));
+ if (!S_ISDIR(mscriptstab.st_mode))
+ ohshit(_("control directory is not a directory"));
+ if ((mscriptstab.st_mode & 07757) != 0755)
+ ohshit(_("control directory has bad permissions %03lo "
+ "(must be >=0755 and <=0775)"),
+ (unsigned long)(mscriptstab.st_mode & 07777));
+
+ for (mscriptp = maintainerscripts; *mscriptp; mscriptp++) {
+ varbuf_reset(&path);
+ varbuf_printf(&path, "%s/%s", ctrldir, *mscriptp);
+ if (!lstat(path.buf, &mscriptstab)) {
+ if (S_ISLNK(mscriptstab.st_mode))
+ continue;
+ if (!S_ISREG(mscriptstab.st_mode))
+ ohshit(_("maintainer script '%.50s' is not a plain file or symlink"),
+ *mscriptp);
+ if ((mscriptstab.st_mode & 07557) != 0555)
+ ohshit(_("maintainer script '%.50s' has bad permissions %03lo "
+ "(must be >=0555 and <=0775)"),
+ *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777));
+ } else if (errno != ENOENT) {
+ ohshite(_("maintainer script '%.50s' is not stattable"), *mscriptp);
+ }
+ }
+
+ varbuf_destroy(&path);
+}
+
+/**
+ * Check if conffiles contains sane information.
+ */
+static void
+check_conffiles(const char *ctrldir, const char *rootdir)
+{
+ FILE *cf;
+ struct varbuf controlfile = VARBUF_INIT;
+ char conffilenamebuf[MAXCONFFILENAME + 1];
+ struct file_info *conffiles_head = NULL;
+ struct file_info *conffiles_tail = NULL;
+
+ varbuf_printf(&controlfile, "%s/%s", ctrldir, CONFFILESFILE);
+
+ cf = fopen(controlfile.buf, "r");
+ if (cf == NULL) {
+ if (errno == ENOENT) {
+ varbuf_destroy(&controlfile);
+ return;
+ }
+
+ ohshite(_("error opening conffiles file"));
+ }
+
+ while (fgets(conffilenamebuf, MAXCONFFILENAME + 1, cf)) {
+ struct stat controlstab;
+ char *conffilename = conffilenamebuf;
+ int n;
+ bool remove_on_upgrade = false;
+
+ n = strlen(conffilename);
+ if (!n)
+ ohshite(_("empty string from fgets reading conffiles"));
+
+ if (conffilename[n - 1] != '\n')
+ ohshit(_("conffile name '%s' is too long, or missing final newline"),
+ conffilename);
+
+ conffilename[--n] = '\0';
+
+ if (c_isspace(conffilename[0])) {
+ /* The conffiles lines cannot start with whitespace; by handling this
+ * case now, we simplify the remaining code. Move past the whitespace
+ * to give a better error. */
+ while (c_isspace(conffilename[0]))
+ conffilename++;
+ if (conffilename[0] == '\0')
+ ohshit(_("empty and whitespace-only lines are not allowed in "
+ "conffiles"));
+ ohshit(_("line with conffile filename '%s' has leading white spaces"),
+ conffilename);
+ }
+
+ if (conffilename[0] != '/') {
+ char *flag = conffilename;
+ char *flag_end = strchr(flag, ' ');
+
+ if (flag_end) {
+ conffilename = flag_end + 1;
+ n -= conffilename - flag;
+ }
+
+ /* If no flag separator is found, assume a missing leading slash. */
+ if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
+ ohshit(_("conffile name '%s' is not an absolute pathname"), conffilename);
+
+ flag_end[0] = '\0';
+
+ /* Otherwise assume a missing filename after the flag separator. */
+ if (conffilename[0] == '\0')
+ ohshit(_("conffile name missing after flag '%s'"), flag);
+
+ if (strcmp(flag, "remove-on-upgrade") == 0)
+ remove_on_upgrade = true;
+ else
+ ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
+ }
+
+ varbuf_reset(&controlfile);
+ varbuf_printf(&controlfile, "%s%s", rootdir, conffilename);
+ if (lstat(controlfile.buf, &controlstab)) {
+ if (errno == ENOENT) {
+ if ((n > 1) && c_isspace(conffilename[n - 1]))
+ warning(_("conffile filename '%s' contains trailing white spaces"),
+ conffilename);
+ if (!remove_on_upgrade)
+ ohshit(_("conffile '%.250s' does not appear in package"), conffilename);
+ } else
+ ohshite(_("conffile '%.250s' is not stattable"), conffilename);
+ } else if (remove_on_upgrade) {
+ ohshit(_("conffile '%s' is present but is requested to be removed"),
+ conffilename);
+ } else if (!S_ISREG(controlstab.st_mode)) {
+ warning(_("conffile '%s' is not a plain file"), conffilename);
+ }
+
+ if (file_info_find_name(conffiles_head, conffilename)) {
+ warning(_("conffile name '%s' is duplicated"), conffilename);
+ } else {
+ struct file_info *conffile;
+
+ conffile = file_info_new(conffilename);
+ file_info_list_append(&conffiles_head, &conffiles_tail, conffile);
+ }
+ }
+
+ file_info_list_free(conffiles_head);
+ varbuf_destroy(&controlfile);
+
+ if (ferror(cf))
+ ohshite(_("error reading conffiles file"));
+ fclose(cf);
+}
+
+/**
+ * Check the control file.
+ *
+ * @param ctrldir The directory from where to build the binary package.
+ * @return The pkginfo struct from the parsed control file.
+ */
+static struct pkginfo *
+check_control_file(const char *ctrldir)
+{
+ struct pkginfo *pkg;
+ char *controlfile;
+
+ controlfile = str_fmt("%s/%s", ctrldir, CONTROLFILE);
+ parsedb(controlfile, pdb_parse_binary, &pkg);
+
+ if (strspn(pkg->set->name, "abcdefghijklmnopqrstuvwxyz0123456789+-.") !=
+ strlen(pkg->set->name))
+ ohshit(_("package name has characters that aren't lowercase alphanums or '-+.'"));
+ if (pkg->available.arch->type == DPKG_ARCH_NONE ||
+ pkg->available.arch->type == DPKG_ARCH_EMPTY)
+ ohshit(_("package architecture is missing or empty"));
+ if (pkg->priority == PKG_PRIO_OTHER)
+ warning(_("'%s' contains user-defined Priority value '%s'"),
+ controlfile, pkg->otherpriority);
+
+ free(controlfile);
+
+ return pkg;
+}
+
+/**
+ * Perform some sanity checks on the to-be-built package control area.
+ *
+ * @param ctrldir The directory from where to build the binary package.
+ * @return The pkginfo struct from the parsed control file.
+ */
+static struct pkginfo *
+check_control_area(const char *ctrldir, const char *rootdir)
+{
+ struct pkginfo *pkg;
+ int warns;
+
+ /* Start by reading in the control file so we can check its contents. */
+ pkg = check_control_file(ctrldir);
+ check_file_perms(ctrldir);
+ check_conffiles(ctrldir, rootdir);
+
+ warns = warning_get_count();
+ if (warns)
+ warning(P_("ignoring %d warning about the control file(s)",
+ "ignoring %d warnings about the control file(s)", warns),
+ warns);
+
+ return pkg;
+}
+
+/**
+ * Generate the pathname for the destination binary package.
+ *
+ * If the pathname cannot be computed, because the destination is a directory,
+ * then NULL will be returned.
+ *
+ * @param dir The directory from where to build the binary package.
+ * @param dest The destination name, either a file or directory name.
+ * @return The pathname for the package being built.
+ */
+static char *
+gen_dest_pathname(const char *dir, const char *dest)
+{
+ if (dest) {
+ struct stat dest_stab;
+
+ if (stat(dest, &dest_stab)) {
+ if (errno != ENOENT)
+ ohshite(_("unable to check for existence of archive '%.250s'"), dest);
+ } else if (S_ISDIR(dest_stab.st_mode)) {
+ /* Need to compute the destination name from the package control file. */
+ return NULL;
+ }
+
+ return m_strdup(dest);
+ } else {
+ char *pathname;
+
+ pathname = m_malloc(strlen(dir) + sizeof(DEBEXT));
+ strcpy(pathname, dir);
+ path_trim_slash_slashdot(pathname);
+ strcat(pathname, DEBEXT);
+
+ return pathname;
+ }
+}
+
+/**
+ * Generate the pathname for the destination binary package from control file.
+ *
+ * @return The pathname for the package being built.
+ */
+static char *
+gen_dest_pathname_from_pkg(const char *dir, struct pkginfo *pkg)
+{
+ return str_fmt("%s/%s_%s_%s%s", dir, pkg->set->name,
+ versiondescribe(&pkg->available.version, vdew_never),
+ pkg->available.arch->name, DEBEXT);
+}
+
+typedef void filenames_feed_func(const char *dir, int fd_out);
+
+struct tar_pack_options {
+ intmax_t timestamp;
+ const char *mode;
+ bool root_owner_group;
+};
+
+/**
+ * Pack the contents of a directory into a tarball.
+ */
+static void
+tarball_pack(const char *dir, filenames_feed_func *tar_filenames_feeder,
+ struct tar_pack_options *options,
+ struct compress_params *tar_compress_params, int fd_out)
+{
+ int pipe_filenames[2], pipe_tarball[2];
+ pid_t pid_tar, pid_comp;
+
+ /* Fork off a tar. We will feed it a list of filenames on stdin later. */
+ m_pipe(pipe_filenames);
+ m_pipe(pipe_tarball);
+ pid_tar = subproc_fork();
+ if (pid_tar == 0) {
+ struct command cmd;
+ char mtime[50];
+
+ m_dup2(pipe_filenames[0], 0);
+ close(pipe_filenames[0]);
+ close(pipe_filenames[1]);
+ m_dup2(pipe_tarball[1], 1);
+ close(pipe_tarball[0]);
+ close(pipe_tarball[1]);
+
+ if (chdir(dir))
+ ohshite(_("failed to chdir to '%.255s'"), dir);
+
+ snprintf(mtime, sizeof(mtime), "@%jd", options->timestamp);
+
+ command_init(&cmd, TAR, "tar -cf");
+ command_add_args(&cmd, "tar", "-cf", "-", "--format=gnu",
+ "--mtime", mtime, "--clamp-mtime", NULL);
+ /* Mode might become a positional argument, pass it before -T. */
+ if (options->mode)
+ command_add_args(&cmd, "--mode", options->mode, NULL);
+ if (options->root_owner_group)
+ command_add_args(&cmd, "--owner", "root:0", "--group", "root:0", NULL);
+ command_add_args(&cmd, "--null", "--no-unquote", "--no-recursion",
+ "-T", "-", NULL);
+ command_exec(&cmd);
+ }
+ close(pipe_filenames[0]);
+ close(pipe_tarball[1]);
+
+ /* Of course we should not forget to compress the archive as well. */
+ pid_comp = subproc_fork();
+ if (pid_comp == 0) {
+ close(pipe_filenames[1]);
+ compress_filter(tar_compress_params, pipe_tarball[0], fd_out,
+ _("compressing tar member"));
+ exit(0);
+ }
+ close(pipe_tarball[0]);
+
+ /* All the pipes are set, now lets start feeding filenames to tar. */
+ tar_filenames_feeder(dir, pipe_filenames[1]);
+
+ /* All done, clean up wait for tar and <compress> to finish their job. */
+ close(pipe_filenames[1]);
+ subproc_reap(pid_comp, _("<compress> from tar -cf"), 0);
+ subproc_reap(pid_tar, "tar -cf", 0);
+}
+
+static intmax_t
+parse_timestamp(const char *value)
+{
+ intmax_t timestamp;
+ char *end;
+
+ errno = 0;
+ timestamp = strtoimax(value, &end, 10);
+ if (value == end || *end || errno != 0)
+ ohshite(_("unable to parse timestamp '%.255s'"), value);
+
+ return timestamp;
+}
+
+/**
+ * Overly complex function that builds a .deb file.
+ */
+int
+do_build(const char *const *argv)
+{
+ struct compress_params control_compress_params;
+ struct tar_pack_options tar_options;
+ struct dpkg_error err;
+ struct dpkg_ar *ar;
+ intmax_t timestamp;
+ const char *timestamp_str;
+ const char *dir, *dest;
+ char *ctrldir;
+ char *debar;
+ char *tfbuf;
+ int gzfd;
+
+ /* Decode our arguments. */
+ dir = *argv++;
+ if (!dir)
+ badusage(_("--%s needs a <directory> argument"), cipaction->olong);
+
+ dest = *argv++;
+ if (dest && *argv)
+ badusage(_("--%s takes at most two arguments"), cipaction->olong);
+
+ debar = gen_dest_pathname(dir, dest);
+ ctrldir = str_fmt("%s/%s", dir, BUILDCONTROLDIR);
+
+ /* Perform some sanity checks on the to-be-build package. */
+ if (nocheckflag) {
+ if (debar == NULL)
+ ohshit(_("target is directory - cannot skip control file check"));
+ warning(_("not checking contents of control area"));
+ info(_("building an unknown package in '%s'."), debar);
+ } else {
+ struct pkginfo *pkg;
+
+ pkg = check_control_area(ctrldir, dir);
+ if (debar == NULL)
+ debar = gen_dest_pathname_from_pkg(dest, pkg);
+ info(_("building package '%s' in '%s'."), pkg->set->name, debar);
+ }
+ m_output(stdout, _("<standard output>"));
+
+ timestamp_str = getenv("SOURCE_DATE_EPOCH");
+ if (timestamp_str)
+ timestamp = parse_timestamp(timestamp_str);
+ else
+ timestamp = time(NULL);
+
+ /* Now that we have verified everything it is time to actually
+ * build something. Let's start by making the ar-wrapper. */
+ ar = dpkg_ar_create(debar, 0644);
+
+ dpkg_ar_set_mtime(ar, timestamp);
+
+ unsetenv("TAR_OPTIONS");
+
+ /* Create a temporary file to store the control data in. Immediately
+ * unlink our temporary file so others can't mess with it. */
+ tfbuf = path_make_temp_template("dpkg-deb");
+ gzfd = mkstemp(tfbuf);
+ if (gzfd == -1)
+ ohshite(_("failed to make temporary file (%s)"), _("control member"));
+ /* Make sure it's gone, the fd will remain until we close it. */
+ if (unlink(tfbuf))
+ ohshit(_("failed to unlink temporary file (%s), %s"), _("control member"),
+ tfbuf);
+ free(tfbuf);
+
+ /* Select the compressor to use for our control archive. */
+ if (opt_uniform_compression) {
+ control_compress_params = compress_params;
+ } else {
+ control_compress_params.type = COMPRESSOR_TYPE_GZIP;
+ control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE;
+ control_compress_params.level = -1;
+ if (!compressor_check_params(&control_compress_params, &err))
+ internerr("invalid control member compressor params: %s", err.str);
+ }
+
+ /* Fork a tar to package the control-section of the package. */
+ tar_options.mode = "u+rw,go=rX";
+ tar_options.timestamp = timestamp;
+ tar_options.root_owner_group = true;
+ tarball_pack(ctrldir, control_treewalk_feed, &tar_options,
+ &control_compress_params, gzfd);
+
+ free(ctrldir);
+
+ if (lseek(gzfd, 0, SEEK_SET))
+ ohshite(_("failed to rewind temporary file (%s)"), _("control member"));
+
+ /* We have our first file for the ar-archive. Write a header for it
+ * to the package and insert it. */
+ if (deb_format.major == 0) {
+ struct stat controlstab;
+ char versionbuf[40];
+
+ if (fstat(gzfd, &controlstab))
+ ohshite(_("failed to stat temporary file (%s)"), _("control member"));
+ sprintf(versionbuf, "%-8s\n%jd\n", OLDARCHIVEVERSION,
+ (intmax_t)controlstab.st_size);
+ if (fd_write(ar->fd, versionbuf, strlen(versionbuf)) < 0)
+ ohshite(_("error writing '%s'"), debar);
+ if (fd_fd_copy(gzfd, ar->fd, -1, &err) < 0)
+ ohshit(_("cannot copy '%s' into archive '%s': %s"), _("control member"),
+ ar->name, err.str);
+ } else if (deb_format.major == 2) {
+ const char deb_magic[] = ARCHIVEVERSION "\n";
+ char adminmember[16 + 1];
+
+ sprintf(adminmember, "%s%s", ADMINMEMBER,
+ compressor_get_extension(control_compress_params.type));
+
+ dpkg_ar_put_magic(ar);
+ dpkg_ar_member_put_mem(ar, DEBMAGIC, deb_magic, strlen(deb_magic));
+ dpkg_ar_member_put_file(ar, adminmember, gzfd, -1);
+ } else {
+ internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor);
+ }
+
+ close(gzfd);
+
+ /* Control is done, now we need to archive the data. */
+ if (deb_format.major == 0) {
+ /* In old format, the data member is just concatenated after the
+ * control member, so we do not need a temporary file and can use
+ * the compression file descriptor. */
+ gzfd = ar->fd;
+ } else if (deb_format.major == 2) {
+ /* Start by creating a new temporary file. Immediately unlink the
+ * temporary file so others can't mess with it. */
+ tfbuf = path_make_temp_template("dpkg-deb");
+ gzfd = mkstemp(tfbuf);
+ if (gzfd == -1)
+ ohshite(_("failed to make temporary file (%s)"), _("data member"));
+ /* Make sure it's gone, the fd will remain until we close it. */
+ if (unlink(tfbuf))
+ ohshit(_("failed to unlink temporary file (%s), %s"), _("data member"),
+ tfbuf);
+ free(tfbuf);
+ } else {
+ internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor);
+ }
+
+ /* Pack the directory into a tarball, feeding files from the callback. */
+ tar_options.mode = NULL;
+ tar_options.timestamp = timestamp;
+ tar_options.root_owner_group = opt_root_owner_group;
+ tarball_pack(dir, file_treewalk_feed, &tar_options, &compress_params, gzfd);
+
+ /* Okay, we have data.tar as well now, add it to the ar wrapper. */
+ if (deb_format.major == 2) {
+ char datamember[16 + 1];
+
+ sprintf(datamember, "%s%s", DATAMEMBER,
+ compressor_get_extension(compress_params.type));
+
+ if (lseek(gzfd, 0, SEEK_SET))
+ ohshite(_("failed to rewind temporary file (%s)"), _("data member"));
+
+ dpkg_ar_member_put_file(ar, datamember, gzfd, -1);
+
+ close(gzfd);
+ }
+ if (fsync(ar->fd))
+ ohshite(_("unable to sync file '%s'"), ar->name);
+
+ dpkg_ar_close(ar);
+
+ free(debar);
+
+ return 0;
+}
diff --git a/src/deb/dpkg-deb.h b/src/deb/dpkg-deb.h
new file mode 100644
index 0000000..a5e8d39
--- /dev/null
+++ b/src/deb/dpkg-deb.h
@@ -0,0 +1,87 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * dpkg-deb.h - external definitions for this program
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 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 DPKG_DEB_H
+#define DPKG_DEB_H
+
+#include <dpkg/deb-version.h>
+
+action_func do_build;
+action_func do_contents;
+action_func do_control;
+action_func do_showinfo;
+action_func do_info;
+action_func do_field;
+action_func do_extract;
+action_func do_vextract;
+action_func do_raw_extract;
+action_func do_ctrltarfile;
+action_func do_fsystarfile;
+
+extern int opt_verbose;
+extern int opt_root_owner_group;
+extern int opt_uniform_compression;
+extern int debugflag, nocheckflag;
+
+extern struct deb_version deb_format;
+
+enum dpkg_tar_options {
+ /** Output the tar file directly, without any processing. */
+ DPKG_TAR_PASSTHROUGH = 0,
+ /** List tar files. */
+ DPKG_TAR_LIST = DPKG_BIT(0),
+ /** Extract tar files. */
+ DPKG_TAR_EXTRACT = DPKG_BIT(1),
+ /** Preserve tar permissions on extract. */
+ DPKG_TAR_PERMS = DPKG_BIT(2),
+ /** Do not set tar mtime on extract. */
+ DPKG_TAR_NOMTIME = DPKG_BIT(3),
+ /** Guarantee extraction into a new directory, abort if it exists. */
+ DPKG_TAR_CREATE_DIR = DPKG_BIT(4),
+};
+
+void extracthalf(const char *debar, const char *dir,
+ enum dpkg_tar_options taroption, int admininfo);
+
+extern const char *showformat;
+extern struct compress_params compress_params;
+
+#define ARCHIVEVERSION "2.0"
+
+#define BUILDCONTROLDIR "DEBIAN"
+#define EXTRACTCONTROLDIR BUILDCONTROLDIR
+
+#define OLDARCHIVEVERSION "0.939000"
+
+#define OLDDEBDIR "DEBIAN"
+#define OLDOLDDEBDIR ".DEBIAN"
+
+#define DEBMAGIC "debian-binary"
+#define ADMINMEMBER "control.tar"
+#define DATAMEMBER "data.tar"
+
+#ifdef PATH_MAX
+# define INTERPRETER_MAX PATH_MAX
+#else
+# define INTERPRETER_MAX 1024
+#endif
+
+#endif /* DPKG_DEB_H */
diff --git a/src/deb/extract.c b/src/deb/extract.c
new file mode 100644
index 0000000..73612a4
--- /dev/null
+++ b/src/deb/extract.c
@@ -0,0 +1,507 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * extract.c - extracting archives
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/fdio.h>
+#include <dpkg/buffer.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/compress.h>
+#include <dpkg/ar.h>
+#include <dpkg/deb-version.h>
+#include <dpkg/options.h>
+
+#include "dpkg-deb.h"
+
+static void
+movecontrolfiles(const char *dir, const char *thing)
+{
+ char *cmd;
+ pid_t pid;
+
+ cmd = str_fmt("mv %s/%s/* %s/ && rmdir %s/%s", dir, thing, dir, dir, thing);
+ pid = subproc_fork();
+ if (pid == 0) {
+ command_shell(cmd, _("shell command to move files"));
+ }
+ subproc_reap(pid, _("shell command to move files"), 0);
+ free(cmd);
+}
+
+static void DPKG_ATTR_NORET
+read_fail(int rc, const char *filename, const char *what)
+{
+ if (rc >= 0)
+ ohshit(_("unexpected end of file in %s in %.255s"),what,filename);
+ else
+ ohshite(_("error reading %s from file %.255s"), what, filename);
+}
+
+static ssize_t
+read_line(int fd, char *buf, size_t min_size, size_t max_size)
+{
+ ssize_t line_size = 0;
+ size_t n = min_size;
+
+ while (line_size < (ssize_t)max_size) {
+ ssize_t r;
+ char *nl;
+
+ r = fd_read(fd, buf + line_size, n);
+ if (r <= 0)
+ return r;
+
+ nl = memchr(buf + line_size, '\n', r);
+ line_size += r;
+
+ if (nl != NULL) {
+ nl[1] = '\0';
+ return line_size;
+ }
+
+ n = 1;
+ }
+
+ buf[line_size] = '\0';
+ return line_size;
+}
+
+void
+extracthalf(const char *debar, const char *dir,
+ enum dpkg_tar_options taroption, int admininfo)
+{
+ struct dpkg_error err;
+ const char *errstr;
+ struct dpkg_ar *ar;
+ char versionbuf[40];
+ struct deb_version version;
+ off_t ctrllennum, memberlen = 0;
+ ssize_t r;
+ int dummy;
+ pid_t c1=0,c2,c3;
+ int p1[2], p2[2];
+ int p2_out;
+ char nlc;
+ int adminmember = -1;
+ bool header_done;
+ struct compress_params decompress_params = {
+ .type = COMPRESSOR_TYPE_GZIP,
+ .threads_max = compress_params.threads_max,
+ };
+
+ ar = dpkg_ar_open(debar);
+
+ r = read_line(ar->fd, versionbuf, strlen(DPKG_AR_MAGIC), sizeof(versionbuf) - 1);
+ if (r <= 0)
+ read_fail(r, debar, _("archive magic version number"));
+
+ if (strcmp(versionbuf, DPKG_AR_MAGIC) == 0) {
+ ctrllennum= 0;
+ header_done = false;
+ for (;;) {
+ struct dpkg_ar_hdr arh;
+
+ r = fd_read(ar->fd, &arh, sizeof(arh));
+ if (r != sizeof(arh))
+ read_fail(r, debar, _("archive member header"));
+
+ if (dpkg_ar_member_is_illegal(&arh))
+ ohshit(_("file '%.250s' is corrupt - bad archive header magic"), debar);
+
+ dpkg_ar_normalize_name(&arh);
+
+ memberlen = dpkg_ar_member_get_size(ar, &arh);
+ if (!header_done) {
+ char *infobuf;
+
+ if (strncmp(arh.ar_name, DEBMAGIC, sizeof(arh.ar_name)) != 0)
+ ohshit(_("file '%.250s' is not a Debian binary archive (try dpkg-split?)"),
+ debar);
+ infobuf= m_malloc(memberlen+1);
+ r = fd_read(ar->fd, infobuf, memberlen + (memberlen & 1));
+ if (r != (memberlen + (memberlen & 1)))
+ read_fail(r, debar, _("archive information header member"));
+ infobuf[memberlen] = '\0';
+
+ if (strchr(infobuf, '\n') == NULL)
+ ohshit(_("archive has no newlines in header"));
+ errstr = deb_version_parse(&version, infobuf);
+ if (errstr)
+ ohshit(_("archive has invalid format version: %s"), errstr);
+ if (version.major != 2)
+ ohshit(_("archive is format version %d.%d; get a newer dpkg-deb"),
+ version.major, version.minor);
+
+ free(infobuf);
+
+ header_done = true;
+ } else if (arh.ar_name[0] == '_') {
+ /* Members with ‘_’ are noncritical, and if we don't understand
+ * them we skip them. */
+ if (fd_skip(ar->fd, memberlen + (memberlen & 1), &err) < 0)
+ ohshit(_("cannot skip archive member from '%s': %s"), ar->name, err.str);
+ } else {
+ if (strncmp(arh.ar_name, ADMINMEMBER, strlen(ADMINMEMBER)) == 0) {
+ const char *extension = arh.ar_name + strlen(ADMINMEMBER);
+
+ adminmember = 1;
+ decompress_params.type = compressor_find_by_extension(extension);
+ if (decompress_params.type != COMPRESSOR_TYPE_NONE &&
+ decompress_params.type != COMPRESSOR_TYPE_GZIP &&
+ decompress_params.type != COMPRESSOR_TYPE_ZSTD &&
+ decompress_params.type != COMPRESSOR_TYPE_XZ)
+ ohshit(_("archive '%s' uses unknown compression for member '%.*s', "
+ "giving up"),
+ debar, (int)sizeof(arh.ar_name), arh.ar_name);
+
+ if (ctrllennum != 0)
+ ohshit(_("archive '%.250s' contains two control members, giving up"),
+ debar);
+ ctrllennum = memberlen;
+ } else {
+ if (adminmember != 1)
+ ohshit(_("archive '%s' has premature member '%.*s' before '%s', "
+ "giving up"),
+ debar, (int)sizeof(arh.ar_name), arh.ar_name, ADMINMEMBER);
+
+ if (strncmp(arh.ar_name, DATAMEMBER, strlen(DATAMEMBER)) == 0) {
+ const char *extension = arh.ar_name + strlen(DATAMEMBER);
+
+ adminmember= 0;
+ decompress_params.type = compressor_find_by_extension(extension);
+ if (decompress_params.type == COMPRESSOR_TYPE_UNKNOWN)
+ ohshit(_("archive '%s' uses unknown compression for member '%.*s', "
+ "giving up"),
+ debar, (int)sizeof(arh.ar_name), arh.ar_name);
+ } else {
+ ohshit(_("archive '%s' has premature member '%.*s' before '%s', "
+ "giving up"),
+ debar, (int)sizeof(arh.ar_name), arh.ar_name, DATAMEMBER);
+ }
+ }
+ if (!adminmember != !admininfo) {
+ if (fd_skip(ar->fd, memberlen + (memberlen & 1), &err) < 0)
+ ohshit(_("cannot skip archive member from '%s': %s"), ar->name, err.str);
+ } else {
+ /* Yes! - found it. */
+ break;
+ }
+ }
+ }
+
+ if (admininfo >= 2) {
+ printf(_(" new Debian package, version %d.%d.\n"
+ " size %jd bytes: control archive=%jd bytes.\n"),
+ version.major, version.minor,
+ (intmax_t)ar->size, (intmax_t)ctrllennum);
+ m_output(stdout, _("<standard output>"));
+ }
+ } else if (strncmp(versionbuf, "0.93", 4) == 0) {
+ char ctrllenbuf[40];
+ int l;
+
+ l = strlen(versionbuf);
+
+ if (strchr(versionbuf, '\n') == NULL)
+ ohshit(_("archive has no newlines in header"));
+ errstr = deb_version_parse(&version, versionbuf);
+ if (errstr)
+ ohshit(_("archive has invalid format version: %s"), errstr);
+
+ r = read_line(ar->fd, ctrllenbuf, 1, sizeof(ctrllenbuf) - 1);
+ if (r <= 0)
+ read_fail(r, debar, _("archive control member size"));
+ if (sscanf(ctrllenbuf, "%jd%c%d", (intmax_t *)&ctrllennum, &nlc, &dummy) != 2 ||
+ nlc != '\n')
+ ohshit(_("archive has malformed control member size '%s'"), ctrllenbuf);
+
+ if (admininfo) {
+ memberlen = ctrllennum;
+ } else {
+ memberlen = ar->size - ctrllennum - strlen(ctrllenbuf) - l;
+ if (fd_skip(ar->fd, ctrllennum, &err) < 0)
+ ohshit(_("cannot skip archive control member from '%s': %s"), ar->name,
+ err.str);
+ }
+
+ if (admininfo >= 2) {
+ printf(_(" old Debian package, version %d.%d.\n"
+ " size %jd bytes: control archive=%jd, main archive=%jd.\n"),
+ version.major, version.minor,
+ (intmax_t)ar->size, (intmax_t)ctrllennum,
+ (intmax_t)(ar->size - ctrllennum - strlen(ctrllenbuf) - l));
+ m_output(stdout, _("<standard output>"));
+ }
+ } else {
+ if (strncmp(versionbuf, "!<arch>", 7) == 0) {
+ notice(_("file looks like it might be an archive which has been\n"
+ " corrupted by being downloaded in ASCII mode"));
+ }
+
+ ohshit(_("'%.255s' is not a Debian format archive"), debar);
+ }
+
+ m_pipe(p1);
+ c1 = subproc_fork();
+ if (!c1) {
+ close(p1[0]);
+ if (fd_fd_copy(ar->fd, p1[1], memberlen, &err) < 0)
+ ohshit(_("cannot copy archive member from '%s' to decompressor pipe: %s"),
+ ar->name, err.str);
+ if (close(p1[1]))
+ ohshite(_("cannot close decompressor pipe"));
+ exit(0);
+ }
+ close(p1[1]);
+
+ if (taroption) {
+ m_pipe(p2);
+ p2_out = p2[1];
+ } else {
+ p2_out = 1;
+ }
+
+ c2 = subproc_fork();
+ if (!c2) {
+ if (taroption)
+ close(p2[0]);
+ decompress_filter(&decompress_params, p1[0], p2_out,
+ _("decompressing archive '%s' (size=%jd) member '%s'"),
+ ar->name, (intmax_t)ar->size,
+ admininfo ? ADMINMEMBER : DATAMEMBER);
+ exit(0);
+ }
+ close(p1[0]);
+ dpkg_ar_close(ar);
+
+ if (taroption) {
+ close(p2[1]);
+
+ c3 = subproc_fork();
+ if (!c3) {
+ struct command cmd;
+
+ command_init(&cmd, TAR, "tar");
+ command_add_arg(&cmd, "tar");
+
+ if ((taroption & DPKG_TAR_LIST) && (taroption & DPKG_TAR_EXTRACT))
+ command_add_arg(&cmd, "-xv");
+ else if (taroption & DPKG_TAR_EXTRACT)
+ command_add_arg(&cmd, "-x");
+ else if (taroption & DPKG_TAR_LIST)
+ command_add_arg(&cmd, "-tv");
+ else
+ internerr("unknown or missing tar action '%d'", taroption);
+
+ if (taroption & DPKG_TAR_PERMS)
+ command_add_arg(&cmd, "-p");
+ if (taroption & DPKG_TAR_NOMTIME)
+ command_add_arg(&cmd, "-m");
+
+ command_add_arg(&cmd, "-f");
+ command_add_arg(&cmd, "-");
+ command_add_arg(&cmd, "--warning=no-timestamp");
+
+ m_dup2(p2[0],0);
+ close(p2[0]);
+
+ unsetenv("TAR_OPTIONS");
+
+ if (dir) {
+ if (mkdir(dir, 0777) != 0) {
+ if (errno != EEXIST)
+ ohshite(_("failed to create directory"));
+
+ if (taroption & DPKG_TAR_CREATE_DIR)
+ ohshite(_("unexpected pre-existing pathname %s"), dir);
+ }
+ if (chdir(dir) != 0)
+ ohshite(_("failed to chdir to directory"));
+ }
+
+ command_exec(&cmd);
+ }
+ close(p2[0]);
+ subproc_reap(c3, "tar", 0);
+ }
+
+ subproc_reap(c2, _("<decompress>"), SUBPROC_NOPIPE);
+ if (c1 != -1)
+ subproc_reap(c1, _("paste"), 0);
+ if (version.major == 0 && admininfo) {
+ /* Handle the version as a float to preserve the behaviour of old code,
+ * because even if the format is defined to be padded by 0's that might
+ * not have been always true for really ancient versions... */
+ while (version.minor && (version.minor % 10) == 0)
+ version.minor /= 10;
+
+ if (version.minor == 931)
+ movecontrolfiles(dir, OLDOLDDEBDIR);
+ else if (version.minor == 932 || version.minor == 933)
+ movecontrolfiles(dir, OLDDEBDIR);
+ }
+}
+
+int
+do_ctrltarfile(const char *const *argv)
+{
+ const char *debar;
+
+ debar = *argv++;
+ if (debar == NULL)
+ badusage(_("--%s needs a .deb filename argument"), cipaction->olong);
+ if (*argv)
+ badusage(_("--%s takes only one argument (.deb filename)"),
+ cipaction->olong);
+
+ extracthalf(debar, NULL, DPKG_TAR_PASSTHROUGH, 1);
+
+ return 0;
+}
+
+int
+do_fsystarfile(const char *const *argv)
+{
+ const char *debar;
+
+ debar = *argv++;
+ if (debar == NULL)
+ badusage(_("--%s needs a .deb filename argument"),cipaction->olong);
+ if (*argv)
+ badusage(_("--%s takes only one argument (.deb filename)"),cipaction->olong);
+ extracthalf(debar, NULL, DPKG_TAR_PASSTHROUGH, 0);
+
+ return 0;
+}
+
+int
+do_control(const char *const *argv)
+{
+ const char *debar, *dir;
+
+ debar = *argv++;
+ if (debar == NULL)
+ badusage(_("--%s needs a .deb filename argument"), cipaction->olong);
+
+ dir = *argv++;
+ if (dir == NULL)
+ dir = EXTRACTCONTROLDIR;
+ else if (*argv)
+ badusage(_("--%s takes at most two arguments (.deb and directory)"),
+ cipaction->olong);
+
+ extracthalf(debar, dir, DPKG_TAR_EXTRACT, 1);
+
+ return 0;
+}
+
+int
+do_extract(const char *const *argv)
+{
+ const char *debar, *dir;
+ enum dpkg_tar_options options = DPKG_TAR_EXTRACT | DPKG_TAR_PERMS;
+
+ if (opt_verbose)
+ options |= DPKG_TAR_LIST;
+
+ debar = *argv++;
+ if (debar == NULL)
+ badusage(_("--%s needs .deb filename and directory arguments"),
+ cipaction->olong);
+
+ dir = *argv++;
+ if (dir == NULL)
+ badusage(_("--%s needs a target directory.\n"
+ "Perhaps you should be using dpkg --install ?"),
+ cipaction->olong);
+ else if (*argv)
+ badusage(_("--%s takes at most two arguments (.deb and directory)"),
+ cipaction->olong);
+
+ extracthalf(debar, dir, options, 0);
+
+ return 0;
+}
+
+int
+do_vextract(const char *const *argv)
+{
+ /* XXX: Backward compatibility. */
+ opt_verbose = 1;
+ return do_extract(argv);
+}
+
+int
+do_raw_extract(const char *const *argv)
+{
+ enum dpkg_tar_options data_options;
+ const char *debar, *dir;
+ char *control_dir;
+
+ debar = *argv++;
+ if (debar == NULL)
+ badusage(_("--%s needs .deb filename and directory arguments"),
+ cipaction->olong);
+ else if (strcmp(debar, "-") == 0)
+ badusage(_("--%s does not support (yet) reading the .deb from standard input"),
+ cipaction->olong);
+
+ dir = *argv++;
+ if (dir == NULL)
+ badusage(_("--%s needs a target directory.\n"
+ "Perhaps you should be using dpkg --install ?"),
+ cipaction->olong);
+ else if (*argv)
+ badusage(_("--%s takes at most two arguments (.deb and directory)"),
+ cipaction->olong);
+
+ control_dir = str_fmt("%s/%s", dir, EXTRACTCONTROLDIR);
+
+ data_options = DPKG_TAR_EXTRACT | DPKG_TAR_PERMS;
+ if (opt_verbose)
+ data_options |= DPKG_TAR_LIST;
+
+ extracthalf(debar, dir, data_options, 0);
+ extracthalf(debar, control_dir, DPKG_TAR_EXTRACT | DPKG_TAR_CREATE_DIR, 1);
+
+ free(control_dir);
+
+ return 0;
+}
diff --git a/src/deb/info.c b/src/deb/info.c
new file mode 100644
index 0000000..794eeb0
--- /dev/null
+++ b/src/deb/info.c
@@ -0,0 +1,305 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * info.c - providing information
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2001 Wichert Akkerman
+ * Copyright © 2007-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 <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdint.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/parsedump.h>
+#include <dpkg/pkg-format.h>
+#include <dpkg/buffer.h>
+#include <dpkg/path.h>
+#include <dpkg/options.h>
+
+#include "dpkg-deb.h"
+
+static void cu_info_prepare(int argc, void **argv) {
+ char *dir;
+
+ dir = argv[0];
+ path_remove_tree(dir);
+ free(dir);
+}
+
+static void info_prepare(const char *const **argvp,
+ const char **debarp,
+ const char **dirp,
+ int admininfo) {
+ char *dbuf;
+
+ *debarp= *(*argvp)++;
+ if (!*debarp) badusage(_("--%s needs a .deb filename argument"),cipaction->olong);
+
+ dbuf = mkdtemp(path_make_temp_template("dpkg-deb"));
+ if (!dbuf)
+ ohshite(_("unable to create temporary directory"));
+ *dirp = dbuf;
+
+ push_cleanup(cu_info_prepare, -1, 1, (void *)dbuf);
+ extracthalf(*debarp, dbuf, DPKG_TAR_EXTRACT | DPKG_TAR_NOMTIME, admininfo);
+}
+
+static int ilist_select(const struct dirent *de) {
+ return strcmp(de->d_name,".") && strcmp(de->d_name,"..");
+}
+
+static void
+info_spew(const char *debar, const char *dir, const char *const *argv)
+{
+ struct dpkg_error err;
+ const char *component;
+ struct varbuf controlfile = VARBUF_INIT;
+ int fd;
+ int re= 0;
+
+ while ((component = *argv++) != NULL) {
+ varbuf_reset(&controlfile);
+ varbuf_printf(&controlfile, "%s/%s", dir, component);
+
+ fd = open(controlfile.buf, O_RDONLY);
+ if (fd >= 0) {
+ if (fd_fd_copy(fd, 1, -1, &err) < 0)
+ ohshit(_("cannot extract control file '%s' from '%s': %s"),
+ controlfile.buf, debar, err.str);
+ close(fd);
+ } else if (errno == ENOENT) {
+ notice(_("'%.255s' contains no control component '%.255s'"),
+ debar, component);
+ re++;
+ } else {
+ ohshite(_("open component '%.255s' (in %.255s) failed in an unexpected way"),
+ component, dir);
+ }
+ }
+ varbuf_destroy(&controlfile);
+
+ if (re > 0)
+ ohshit(P_("%d requested control component is missing",
+ "%d requested control components are missing", re), re);
+}
+
+static void
+info_list(const char *debar, const char *dir)
+{
+ char interpreter[INTERPRETER_MAX+1], *p;
+ int il, lines;
+ struct varbuf controlfile = VARBUF_INIT;
+ struct dirent **cdlist, *cdep;
+ int cdn, n;
+ FILE *cc;
+ struct stat stab;
+ int c;
+
+ cdn = scandir(dir, &cdlist, &ilist_select, alphasort);
+ if (cdn == -1)
+ ohshite(_("cannot scan directory '%.255s'"), dir);
+
+ for (n = 0; n < cdn; n++) {
+ cdep = cdlist[n];
+
+ varbuf_reset(&controlfile);
+ varbuf_printf(&controlfile, "%s/%s", dir, cdep->d_name);
+
+ if (stat(controlfile.buf, &stab))
+ ohshite(_("cannot stat '%.255s' (in '%.255s')"), cdep->d_name, dir);
+ if (S_ISREG(stab.st_mode)) {
+ cc = fopen(controlfile.buf, "r");
+ if (!cc)
+ ohshite(_("cannot open '%.255s' (in '%.255s')"), cdep->d_name, dir);
+ lines = 0;
+ interpreter[0] = '\0';
+ if (getc(cc) == '#') {
+ if (getc(cc) == '!') {
+ while ((c= getc(cc))== ' ');
+ p=interpreter; *p++='#'; *p++='!'; il=2;
+ while (il < INTERPRETER_MAX && !c_isspace(c) && c != EOF) {
+ *p++= c; il++; c= getc(cc);
+ }
+ *p = '\0';
+ if (c=='\n') lines++;
+ }
+ }
+ while ((c= getc(cc))!= EOF) { if (c == '\n') lines++; }
+ if (ferror(cc))
+ ohshite(_("failed to read '%.255s' (in '%.255s')"), cdep->d_name, dir);
+ fclose(cc);
+ printf(_(" %7jd bytes, %5d lines %c %-20.127s %.127s\n"),
+ (intmax_t)stab.st_size, lines,
+ (S_IXUSR & stab.st_mode) ? '*' : ' ',
+ cdep->d_name, interpreter);
+ } else {
+ printf(_(" not a plain file %.255s\n"), cdep->d_name);
+ }
+ free(cdep);
+ }
+ free(cdlist);
+
+ varbuf_reset(&controlfile);
+ varbuf_printf(&controlfile, "%s/%s", dir, CONTROLFILE);
+ cc = fopen(controlfile.buf, "r");
+ if (!cc) {
+ if (errno != ENOENT)
+ ohshite(_("failed to read '%.255s' (in '%.255s')"), CONTROLFILE, dir);
+ warning(_("no 'control' file in control archive!"));
+ } else {
+ lines= 1;
+ while ((c= getc(cc))!= EOF) {
+ if (lines)
+ putc(' ', stdout);
+ putc(c, stdout);
+ lines= c=='\n';
+ }
+ if (!lines)
+ putc('\n', stdout);
+
+ if (ferror(cc))
+ ohshite(_("failed to read '%.255s' (in '%.255s')"), CONTROLFILE, dir);
+ fclose(cc);
+ }
+
+ m_output(stdout, _("<standard output>"));
+ varbuf_destroy(&controlfile);
+}
+
+static void
+info_field(const char *debar, const char *dir, const char *const *fields,
+ enum fwriteflags fieldflags)
+{
+ char *controlfile;
+ struct varbuf str = VARBUF_INIT;
+ struct pkginfo *pkg;
+ int i;
+
+ controlfile = str_fmt("%s/%s", dir, CONTROLFILE);
+ parsedb(controlfile, pdb_parse_binary | pdb_ignore_archives, &pkg);
+ free(controlfile);
+
+ for (i = 0; fields[i]; i++) {
+ const struct fieldinfo *field;
+ const struct arbitraryfield *arbfield;
+
+ varbuf_reset(&str);
+ field = find_field_info(fieldinfos, fields[i]);
+ if (field) {
+ field->wcall(&str, pkg, &pkg->available, fieldflags, field);
+ } else {
+ arbfield = find_arbfield_info(pkg->available.arbs, fields[i]);
+ if (arbfield)
+ varbuf_add_arbfield(&str, arbfield, fieldflags);
+ }
+ varbuf_end_str(&str);
+
+ if (fieldflags & fw_printheader)
+ printf("%s", str.buf);
+ else
+ printf("%s\n", str.buf);
+ }
+
+ m_output(stdout, _("<standard output>"));
+
+ varbuf_destroy(&str);
+}
+
+int
+do_showinfo(const char *const *argv)
+{
+ const char *debar, *dir;
+ char *controlfile;
+ struct dpkg_error err;
+ struct pkginfo *pkg;
+ struct pkg_format_node *fmt;
+
+ fmt = pkg_format_parse(showformat, &err);
+ if (!fmt)
+ ohshit(_("error in show format: %s"), err.str);
+
+ info_prepare(&argv, &debar, &dir, 1);
+
+ controlfile = str_fmt("%s/%s", dir, CONTROLFILE);
+ parsedb(controlfile, pdb_parse_binary | pdb_ignore_archives, &pkg);
+ pkg_format_show(fmt, pkg, &pkg->available);
+ pkg_format_free(fmt);
+ free(controlfile);
+
+ return 0;
+}
+
+int
+do_info(const char *const *argv)
+{
+ const char *debar, *dir;
+
+ if (*argv && argv[1]) {
+ info_prepare(&argv, &debar, &dir, 1);
+ info_spew(debar, dir, argv);
+ } else {
+ info_prepare(&argv, &debar, &dir, 2);
+ info_list(debar, dir);
+ }
+
+ return 0;
+}
+
+int
+do_field(const char *const *argv)
+{
+ const char *debar, *dir;
+
+ info_prepare(&argv, &debar, &dir, 1);
+ if (*argv) {
+ info_field(debar, dir, argv, argv[1] != NULL ? fw_printheader : 0);
+ } else {
+ static const char *const controlonly[] = { CONTROLFILE, NULL };
+ info_spew(debar, dir, controlonly);
+ }
+
+ return 0;
+}
+
+int
+do_contents(const char *const *argv)
+{
+ const char *debar = *argv++;
+
+ if (debar == NULL || *argv)
+ badusage(_("--%s takes exactly one argument"), cipaction->olong);
+ extracthalf(debar, NULL, DPKG_TAR_LIST, 0);
+
+ return 0;
+}
diff --git a/src/deb/main.c b/src/deb/main.c
new file mode 100644
index 0000000..4a16738
--- /dev/null
+++ b/src/deb/main.c
@@ -0,0 +1,311 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * main.c - main program
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-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 <sys/types.h>
+#include <sys/wait.h>
+
+#include <limits.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/compress.h>
+#include <dpkg/options.h>
+
+#include "dpkg-deb.h"
+
+const char *showformat = "${Package}\t${Version}\n";
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian '%s' package archive backend version %s.\n"),
+ BACKEND, PACKAGE_RELEASE);
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option>...] <command>\n"
+"\n"), BACKEND);
+
+ printf(_(
+"Commands:\n"
+" -b|--build <directory> [<deb>] Build an archive.\n"
+" -c|--contents <deb> List contents.\n"
+" -I|--info <deb> [<cfile>...] Show info to stdout.\n"
+" -W|--show <deb> Show information on package(s)\n"
+" -f|--field <deb> [<cfield>...] Show field(s) to stdout.\n"
+" -e|--control <deb> [<directory>] Extract control info.\n"
+" -x|--extract <deb> <directory> Extract files.\n"
+" -X|--vextract <deb> <directory> Extract & list files.\n"
+" -R|--raw-extract <deb> <directory>\n"
+" Extract control info and files.\n"
+" --ctrl-tarfile <deb> Output control tarfile.\n"
+" --fsys-tarfile <deb> Output filesystem tarfile.\n"
+"\n"));
+
+ printf(_(
+" -?, --help Show this help message.\n"
+" --version Show the version.\n"
+"\n"));
+
+ printf(_(
+"<deb> is the filename of a Debian format archive.\n"
+"<cfile> is the name of an administrative file component.\n"
+"<cfield> is the name of a field in the main 'control' file.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" -v, --verbose Enable verbose output.\n"
+" -D, --debug Enable debugging output.\n"
+" --showformat=<format> Use alternative format for --show.\n"
+" --deb-format=<format> Select archive format.\n"
+" Allowed values: 0.939000, 2.0 (default).\n"
+" --nocheck Suppress control file check (build bad\n"
+" packages).\n"
+" --root-owner-group Forces the owner and groups to root.\n"
+" --threads-max=<threads> Use at most <threads> with compressor.\n"
+" --[no-]uniform-compression Use the compression params on all members.\n"
+" -z# Set the compression level when building.\n"
+" -Z<type> Set the compression type used when building.\n"
+" Allowed types: gzip, xz, zstd, none.\n"
+" -S<strategy> Set the compression strategy when building.\n"
+" Allowed values: none; extreme (xz);\n"
+" filtered, huffman, rle, fixed (gzip).\n"
+"\n"));
+
+ printf(_(
+"Format syntax:\n"
+" A format is a string that will be output for each package. The format\n"
+" can include the standard escape sequences \\n (newline), \\r (carriage\n"
+" return) or \\\\ (plain backslash). Package information can be included\n"
+" by inserting variable references to package fields using the ${var[;width]}\n"
+" syntax. Fields will be right-aligned unless the width is negative in which\n"
+" case left alignment will be used.\n"));
+
+ printf(_(
+"\n"
+"Use 'dpkg' to install and remove packages from your system, or\n"
+"'apt' or 'aptitude' for user-friendly package management. Packages\n"
+"unpacked using 'dpkg-deb --extract' will be incorrectly installed !\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static const char printforhelp[] =
+ N_("Type dpkg-deb --help for help about manipulating *.deb files;\n"
+ "Type dpkg --help for help about installing and deinstalling packages.");
+
+int debugflag = 0;
+int nocheckflag = 0;
+int opt_verbose = 0;
+int opt_root_owner_group = 0;
+int opt_uniform_compression = 1;
+
+struct deb_version deb_format = DEB_VERSION(2, 0);
+
+static void
+set_deb_format(const struct cmdinfo *cip, const char *value)
+{
+ const char *err;
+
+ err = deb_version_parse(&deb_format, value);
+ if (err)
+ badusage(_("invalid deb format version: %s"), err);
+
+ if ((deb_format.major == 2 && deb_format.minor == 0) ||
+ (deb_format.major == 0 && deb_format.minor == 939000))
+ return;
+ else
+ badusage(_("unknown deb format version: %s"), value);
+}
+
+struct compress_params compress_params = {
+ .type = DPKG_DEB_DEFAULT_COMPRESSOR,
+ .strategy = COMPRESSOR_STRATEGY_NONE,
+ .level = -1,
+ .threads_max = -1,
+};
+
+static long
+parse_compress_level(const char *str)
+{
+ long value;
+ char *end;
+
+ errno = 0;
+ value = strtol(str, &end, 10);
+ if (str == end || *end != '\0' || errno != 0)
+ return 0;
+
+ return value;
+}
+
+static void
+set_compress_level(const struct cmdinfo *cip, const char *value)
+{
+ compress_params.level = dpkg_options_parse_arg_int(cip, value);
+}
+
+static void
+set_compress_strategy(const struct cmdinfo *cip, const char *value)
+{
+ compress_params.strategy = compressor_get_strategy(value);
+ if (compress_params.strategy == COMPRESSOR_STRATEGY_UNKNOWN)
+ badusage(_("unknown compression strategy '%s'!"), value);
+}
+
+static enum compressor_type
+parse_compress_type(const char *value)
+{
+ enum compressor_type type;
+
+ type = compressor_find_by_name(value);
+ if (type == COMPRESSOR_TYPE_UNKNOWN)
+ badusage(_("unknown compression type '%s'!"), value);
+ if (type == COMPRESSOR_TYPE_LZMA)
+ badusage(_("obsolete compression type '%s'; use xz instead"), value);
+ if (type == COMPRESSOR_TYPE_BZIP2)
+ badusage(_("obsolete compression type '%s'; use xz or gzip instead"), value);
+
+ return type;
+}
+
+static void
+set_compress_type(const struct cmdinfo *cip, const char *value)
+{
+ compress_params.type = parse_compress_type(value);
+}
+
+static long
+parse_threads_max(const char *str)
+{
+ long value;
+ char *end;
+
+ errno = 0;
+ value = strtol(str, &end, 10);
+ if (str == end || *end != '\0' || errno != 0)
+ return 0;
+
+ return value;
+}
+
+static void
+set_threads_max(const struct cmdinfo *cip, const char *value)
+{
+ compress_params.threads_max = dpkg_options_parse_arg_int(cip, value);
+}
+
+static const struct cmdinfo cmdinfos[]= {
+ ACTION("build", 'b', 0, do_build),
+ ACTION("contents", 'c', 0, do_contents),
+ ACTION("control", 'e', 0, do_control),
+ ACTION("info", 'I', 0, do_info),
+ ACTION("field", 'f', 0, do_field),
+ ACTION("extract", 'x', 0, do_extract),
+ ACTION("vextract", 'X', 0, do_vextract),
+ ACTION("raw-extract", 'R', 0, do_raw_extract),
+ ACTION("ctrl-tarfile", 0, 0, do_ctrltarfile),
+ ACTION("fsys-tarfile", 0, 0, do_fsystarfile),
+ ACTION("show", 'W', 0, do_showinfo),
+ ACTION("help", '?', 0, usage),
+ ACTION("version", 0, 0, printversion),
+
+ { "deb-format", 0, 1, NULL, NULL, set_deb_format },
+ { "debug", 'D', 0, &debugflag, NULL, NULL, 1 },
+ { "verbose", 'v', 0, &opt_verbose, NULL, NULL, 1 },
+ { "nocheck", 0, 0, &nocheckflag, NULL, NULL, 1 },
+ { "root-owner-group", 0, 0, &opt_root_owner_group, NULL, NULL, 1 },
+ { "threads-max", 0, 1, NULL, NULL, set_threads_max },
+ { "uniform-compression", 0, 0, &opt_uniform_compression, NULL, NULL, 1 },
+ { "no-uniform-compression", 0, 0, &opt_uniform_compression, NULL, NULL, 0 },
+ { NULL, 'z', 1, NULL, NULL, set_compress_level },
+ { NULL, 'Z', 1, NULL, NULL, set_compress_type },
+ { NULL, 'S', 1, NULL, NULL, set_compress_strategy },
+ { "showformat", 0, 1, NULL, &showformat, NULL },
+ { NULL, 0, 0, NULL, NULL, NULL }
+};
+
+int main(int argc, const char *const *argv) {
+ struct dpkg_error err;
+ char *env;
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init(BACKEND);
+ /* XXX: Integrate this into options initialization/parsing. */
+ env = getenv("DPKG_DEB_THREADS_MAX");
+ if (str_is_set(env))
+ compress_params.threads_max = parse_threads_max(env);
+ env = getenv("DPKG_DEB_COMPRESSOR_TYPE");
+ if (str_is_set(env))
+ compress_params.type = parse_compress_type(env);
+ env = getenv("DPKG_DEB_COMPRESSOR_LEVEL");
+ if (str_is_set(env))
+ compress_params.level = parse_compress_level(env);
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ if (!cipaction) badusage(_("need an action option"));
+
+ if (!compressor_check_params(&compress_params, &err))
+ badusage(_("invalid compressor parameters: %s"), err.str);
+
+ if (opt_uniform_compression &&
+ (compress_params.type != COMPRESSOR_TYPE_NONE &&
+ compress_params.type != COMPRESSOR_TYPE_GZIP &&
+ compress_params.type != COMPRESSOR_TYPE_ZSTD &&
+ compress_params.type != COMPRESSOR_TYPE_XZ))
+ badusage(_("unsupported compression type '%s' with uniform compression"),
+ compressor_get_name(compress_params.type));
+
+ ret = cipaction->action(argv);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return ret;
+}
diff --git a/src/divert/main.c b/src/divert/main.c
new file mode 100644
index 0000000..865796d
--- /dev/null
+++ b/src/divert/main.c
@@ -0,0 +1,884 @@
+/*
+ * dpkg-divert - override a package's version of a file
+ *
+ * Copyright © 1995 Ian Jackson
+ * Copyright © 2000, 2001 Wichert Akkerman
+ * Copyright © 2006-2015, 2017-2018 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 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/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/debug.h>
+#include <dpkg/arch.h>
+#include <dpkg/file.h>
+#include <dpkg/glob.h>
+#include <dpkg/buffer.h>
+#include <dpkg/options.h>
+#include <dpkg/db-fsys.h>
+
+
+static const char printforhelp[] = N_(
+"Use --help for help about diverting files.");
+
+static bool opt_pkgname_match_any = true;
+static const char *opt_pkgname = NULL;
+static const char *opt_divertto = NULL;
+
+static int opt_verbose = 1;
+static int opt_test = 0;
+static int opt_rename = -1;
+
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian %s version %s.\n"), dpkg_get_progname(),
+ PACKAGE_RELEASE);
+
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option>...] <command>\n"
+"\n"), dpkg_get_progname());
+
+ printf(_(
+"Commands:\n"
+" [--add] <file> add a diversion.\n"
+" --remove <file> remove the diversion.\n"
+" --list [<glob-pattern>] show file diversions.\n"
+" --listpackage <file> show what package diverts the file.\n"
+" --truename <file> return the diverted file.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --package <package> name of the package whose copy of <file> will not\n"
+" be diverted.\n"
+" --local all packages' versions are diverted.\n"
+" --divert <divert-to> the name used by other packages' versions.\n"
+" --rename actually move the file aside (or back).\n"
+" --no-rename do not move the file aside (or back) (default).\n"
+" --admindir <directory> set the directory with the diversions file.\n"
+" --instdir <directory> set the root directory, but not the admin dir.\n"
+" --root <directory> set the directory of the root filesystem.\n"
+" --test don't do anything, just demonstrate.\n"
+" --quiet quiet operation, minimal output.\n"
+" --help show this help message.\n"
+" --version show the version.\n"
+"\n"));
+
+ printf(_(
+"When adding, default is --local and --divert <original>.distrib.\n"
+"When removing, --package or --local and --divert must match if specified.\n"
+"Package preinst/postrm scripts should always specify --package and --divert.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static void
+opt_rename_setup(void)
+{
+ if (opt_rename >= 0)
+ return;
+
+ opt_rename = 0;
+ warning(_("please specify --no-rename explicitly, the default "
+ "will change to --rename in 1.20.x"));
+}
+
+struct file {
+ char *name;
+ enum {
+ FILE_STAT_INVALID,
+ FILE_STAT_VALID,
+ FILE_STAT_NOFILE,
+ } stat_state;
+ struct stat stat;
+};
+
+static void
+file_init(struct file *f, const char *filename)
+{
+ struct varbuf usefilename = VARBUF_INIT;
+
+ varbuf_add_str(&usefilename, dpkg_fsys_get_dir());
+ varbuf_add_str(&usefilename, filename);
+ varbuf_end_str(&usefilename);
+
+ f->name = varbuf_detach(&usefilename);
+ f->stat_state = FILE_STAT_INVALID;
+}
+
+static void
+file_destroy(struct file *f)
+{
+ free(f->name);
+}
+
+static void
+file_stat(struct file *f)
+{
+ int ret;
+
+ if (f->stat_state != FILE_STAT_INVALID)
+ return;
+
+ ret = lstat(f->name, &f->stat);
+ if (ret && errno != ENOENT)
+ ohshite(_("cannot stat file '%s'"), f->name);
+
+ if (ret == 0)
+ f->stat_state = FILE_STAT_VALID;
+ else
+ f->stat_state = FILE_STAT_NOFILE;
+}
+
+static void
+check_writable_dir(struct file *f)
+{
+ char *tmpname;
+ int tmpfd;
+
+ tmpname = str_fmt("%s%s", f->name, ".dpkg-divert.tmp");
+
+ tmpfd = creat(tmpname, 0600);
+ if (tmpfd < 0)
+ ohshite(_("error checking '%s'"), f->name);
+ close(tmpfd);
+ (void)unlink(tmpname);
+
+ free(tmpname);
+}
+
+static bool
+check_rename(struct file *src, struct file *dst)
+{
+ file_stat(src);
+
+ /* If the source file is not present and we are not going to do
+ * the rename anyway there's no point in checking any further. */
+ if (src->stat_state == FILE_STAT_NOFILE)
+ return false;
+
+ file_stat(dst);
+
+ /*
+ * Unfortunately we have to check for write access in both places,
+ * just having +w is not enough, since people do mount things RO,
+ * and we need to fail before we start mucking around with things.
+ * So we open a file with the same name as the diversions but with
+ * an extension that (hopefully) won't overwrite anything. If it
+ * succeeds, we assume a writable filesystem.
+ */
+
+ check_writable_dir(src);
+ check_writable_dir(dst);
+
+ if (src->stat_state == FILE_STAT_VALID &&
+ dst->stat_state == FILE_STAT_VALID &&
+ !(src->stat.st_dev == dst->stat.st_dev &&
+ src->stat.st_ino == dst->stat.st_ino))
+ ohshit(_("rename involves overwriting '%s' with\n"
+ " different file '%s', not allowed"),
+ dst->name, src->name);
+
+ return true;
+}
+
+static void
+file_copy(const char *src, const char *dst)
+{
+ struct dpkg_error err;
+ char *tmp;
+ int srcfd, dstfd;
+
+ srcfd = open(src, O_RDONLY);
+ if (srcfd < 0)
+ ohshite(_("unable to open file '%s'"), src);
+
+ tmp = str_fmt("%s%s", dst, ".dpkg-divert.tmp");
+ dstfd = creat(tmp, 0600);
+ if (dstfd < 0)
+ ohshite(_("unable to create file '%s'"), tmp);
+
+ push_cleanup(cu_filename, ~ehflag_normaltidy, 1, tmp);
+
+ if (fd_fd_copy(srcfd, dstfd, -1, &err) < 0)
+ ohshit(_("cannot copy '%s' to '%s': %s"), src, tmp, err.str);
+
+ close(srcfd);
+
+ if (fsync(dstfd))
+ ohshite(_("unable to sync file '%s'"), tmp);
+ if (close(dstfd))
+ ohshite(_("unable to close file '%s'"), tmp);
+
+ file_copy_perms(src, tmp);
+
+ if (rename(tmp, dst) != 0)
+ ohshite(_("cannot rename '%s' to '%s'"), tmp, dst);
+
+ free(tmp);
+
+ pop_cleanup(ehflag_normaltidy);
+}
+
+static void
+file_rename(struct file *src, struct file *dst)
+{
+ if (src->stat_state == FILE_STAT_NOFILE)
+ return;
+
+ if (dst->stat_state == FILE_STAT_VALID) {
+ if (unlink(src->name))
+ ohshite(_("rename: remove duplicate old link '%s'"),
+ src->name);
+ } else {
+ if (rename(src->name, dst->name) == 0)
+ return;
+
+ /* If a rename didn't work try moving the file instead. */
+ file_copy(src->name, dst->name);
+
+ if (unlink(src->name))
+ ohshite(_("unable to remove copied source file '%s'"),
+ src->name);
+ }
+}
+
+static void
+diversion_check_filename(const char *filename)
+{
+ if (filename[0] != '/')
+ badusage(_("filename \"%s\" is not absolute"), filename);
+ if (strchr(filename, '\n') != NULL)
+ badusage(_("file may not contain newlines"));
+}
+
+static const char *
+diversion_pkg_name(struct fsys_diversion *d)
+{
+ if (d->pkgset == NULL)
+ return ":";
+ else
+ return d->pkgset->name;
+}
+
+static const char *
+varbuf_diversion(struct varbuf *str, const char *pkgname,
+ const char *filename, const char *divertto)
+{
+ varbuf_reset(str);
+
+ if (pkgname == NULL) {
+ if (divertto == NULL)
+ varbuf_printf(str, _("local diversion of %s"), filename);
+ else
+ varbuf_printf(str, _("local diversion of %s to %s"),
+ filename, divertto);
+ } else {
+ if (divertto == NULL)
+ varbuf_printf(str, _("diversion of %s by %s"),
+ filename, pkgname);
+ else
+ varbuf_printf(str, _("diversion of %s to %s by %s"),
+ filename, divertto, pkgname);
+ }
+
+ return str->buf;
+}
+
+static const char *
+diversion_current(const char *filename)
+{
+ static struct varbuf str = VARBUF_INIT;
+
+ if (opt_pkgname_match_any) {
+ varbuf_reset(&str);
+
+ if (opt_divertto == NULL)
+ varbuf_printf(&str, _("any diversion of %s"), filename);
+ else
+ varbuf_printf(&str, _("any diversion of %s to %s"),
+ filename, opt_divertto);
+ } else {
+ return varbuf_diversion(&str, opt_pkgname, filename, opt_divertto);
+ }
+
+ return str.buf;
+}
+
+static const char *
+diversion_describe(struct fsys_diversion *d)
+{
+ static struct varbuf str = VARBUF_INIT;
+ const char *pkgname;
+ const char *name_from, *name_to;
+
+ if (d->camefrom) {
+ name_from = d->camefrom->name;
+ name_to = d->camefrom->divert->useinstead->name;
+ } else {
+ name_from = d->useinstead->divert->camefrom->name;
+ name_to = d->useinstead->name;
+ }
+
+ if (d->pkgset == NULL)
+ pkgname = NULL;
+ else
+ pkgname = d->pkgset->name;
+
+ return varbuf_diversion(&str, pkgname, name_from, name_to);
+}
+
+static void
+divertdb_write(void)
+{
+ char *dbname;
+ struct atomic_file *file;
+ struct fsys_hash_iter *iter;
+ struct fsys_namenode *namenode;
+
+ dbname = dpkg_db_get_path(DIVERSIONSFILE);
+
+ file = atomic_file_new(dbname, ATOMIC_FILE_BACKUP);
+ atomic_file_open(file);
+
+ iter = fsys_hash_iter_new();
+ while ((namenode = fsys_hash_iter_next(iter))) {
+ struct fsys_diversion *d = namenode->divert;
+
+ if (d == NULL || d->useinstead == NULL)
+ continue;
+
+ fprintf(file->fp, "%s\n%s\n%s\n",
+ d->useinstead->divert->camefrom->name,
+ d->useinstead->name,
+ diversion_pkg_name(d));
+ }
+ fsys_hash_iter_free(iter);
+
+ atomic_file_sync(file);
+ atomic_file_close(file);
+ atomic_file_commit(file);
+ atomic_file_free(file);
+
+ free(dbname);
+}
+
+static bool
+diversion_is_essential(struct fsys_namenode *namenode)
+{
+ struct pkginfo *pkg;
+ struct pkg_hash_iter *pkg_iter;
+ struct fsys_node_pkgs_iter *iter;
+ bool essential = false;
+
+ pkg_iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(pkg_iter))) {
+ if (pkg->installed.essential)
+ ensure_packagefiles_available(pkg);
+ }
+ pkg_hash_iter_free(pkg_iter);
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((pkg = fsys_node_pkgs_iter_next(iter))) {
+ if (pkg->installed.essential) {
+ essential = true;
+ break;
+ }
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ return essential;
+}
+
+static bool
+diversion_is_owned_by_self(struct pkgset *set, struct fsys_namenode *namenode)
+{
+ struct pkginfo *pkg;
+ struct fsys_node_pkgs_iter *iter;
+ bool owned = false;
+
+ if (set == NULL)
+ return false;
+
+ for (pkg = &set->pkg; pkg; pkg = pkg->arch_next)
+ ensure_packagefiles_available(pkg);
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((pkg = fsys_node_pkgs_iter_next(iter))) {
+ if (pkg->set == set) {
+ owned = true;
+ break;
+ }
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ return owned;
+}
+
+static int
+diversion_add(const char *const *argv)
+{
+ const char *filename = argv[0];
+ struct file file_from, file_to;
+ struct fsys_diversion *contest, *altname;
+ struct fsys_namenode *fnn_from, *fnn_to;
+ struct pkgset *pkgset;
+
+ opt_pkgname_match_any = false;
+ opt_rename_setup();
+
+ /* Handle filename. */
+ if (!filename || argv[1])
+ badusage(_("--%s needs a single argument"), cipaction->olong);
+
+ diversion_check_filename(filename);
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ file_init(&file_from, filename);
+ file_stat(&file_from);
+
+ if (file_from.stat_state == FILE_STAT_VALID &&
+ S_ISDIR(file_from.stat.st_mode))
+ badusage(_("cannot divert directories"));
+
+ fnn_from = fsys_hash_find_node(filename, 0);
+
+ /* Handle divertto. */
+ if (opt_divertto == NULL)
+ opt_divertto = str_fmt("%s.distrib", filename);
+
+ if (strcmp(filename, opt_divertto) == 0)
+ badusage(_("cannot divert file '%s' to itself"), filename);
+
+ file_init(&file_to, opt_divertto);
+
+ fnn_to = fsys_hash_find_node(opt_divertto, 0);
+
+ /* Handle package name. */
+ if (opt_pkgname == NULL)
+ pkgset = NULL;
+ else
+ pkgset = pkg_hash_find_set(opt_pkgname);
+
+ /* Check we are not stomping over an existing diversion. */
+ if (fnn_from->divert || fnn_to->divert) {
+ if (fnn_to->divert && fnn_to->divert->camefrom &&
+ strcmp(fnn_to->divert->camefrom->name, filename) == 0 &&
+ fnn_from->divert && fnn_from->divert->useinstead &&
+ strcmp(fnn_from->divert->useinstead->name, opt_divertto) == 0 &&
+ fnn_from->divert->pkgset == pkgset) {
+ if (opt_verbose > 0)
+ printf(_("Leaving '%s'\n"),
+ diversion_describe(fnn_from->divert));
+
+ file_destroy(&file_from);
+ file_destroy(&file_to);
+
+ modstatdb_shutdown();
+
+ return 0;
+ }
+
+ ohshit(_("'%s' clashes with '%s'"),
+ diversion_current(filename),
+ fnn_from->divert ?
+ diversion_describe(fnn_from->divert) :
+ diversion_describe(fnn_to->divert));
+ }
+
+ /* Create new diversion. */
+ contest = nfmalloc(sizeof(*contest));
+ altname = nfmalloc(sizeof(*altname));
+
+ altname->camefrom = fnn_from;
+ altname->camefrom->divert = contest;
+ altname->useinstead = NULL;
+ altname->pkgset = pkgset;
+
+ contest->useinstead = fnn_to;
+ contest->useinstead->divert = altname;
+ contest->camefrom = NULL;
+ contest->pkgset = pkgset;
+
+ /* Update database and file system if needed. */
+ if (opt_verbose > 0)
+ printf(_("Adding '%s'\n"), diversion_describe(contest));
+ if (opt_rename)
+ opt_rename = check_rename(&file_from, &file_to);
+ /* Check we are not renaming a file owned by the diverting pkgset. */
+ if (opt_rename && diversion_is_owned_by_self(pkgset, fnn_from)) {
+ if (opt_verbose > 0)
+ printf(_("Ignoring request to rename file '%s' "
+ "owned by diverting package '%s'\n"),
+ filename, pkgset->name);
+ opt_rename = false;
+ }
+ if (opt_rename && diversion_is_essential(fnn_from))
+ warning(_("diverting file '%s' from an Essential package with "
+ "rename is dangerous, use --no-rename"), filename);
+ if (!opt_test) {
+ divertdb_write();
+ if (opt_rename)
+ file_rename(&file_from, &file_to);
+ }
+
+ file_destroy(&file_from);
+ file_destroy(&file_to);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static bool
+diversion_is_shared(struct pkgset *set, struct fsys_namenode *namenode)
+{
+ const char *archname;
+ struct pkginfo *pkg;
+ struct dpkg_arch *arch;
+ struct fsys_node_pkgs_iter *iter;
+ bool shared = false;
+
+ if (set == NULL)
+ return false;
+
+ archname = getenv("DPKG_MAINTSCRIPT_ARCH");
+ arch = dpkg_arch_find(archname);
+ if (arch->type == DPKG_ARCH_NONE || arch->type == DPKG_ARCH_EMPTY)
+ return false;
+
+ for (pkg = &set->pkg; pkg; pkg = pkg->arch_next)
+ ensure_packagefiles_available(pkg);
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((pkg = fsys_node_pkgs_iter_next(iter))) {
+ if (pkg->set == set && pkg->installed.arch != arch) {
+ shared = true;
+ break;
+ }
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ return shared;
+}
+
+static int
+diversion_remove(const char *const *argv)
+{
+ const char *filename = argv[0];
+ struct fsys_namenode *namenode;
+ struct fsys_diversion *contest, *altname;
+ struct file file_from, file_to;
+ struct pkgset *pkgset;
+
+ opt_rename_setup();
+
+ if (!filename || argv[1])
+ badusage(_("--%s needs a single argument"), cipaction->olong);
+
+ diversion_check_filename(filename);
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ namenode = fsys_hash_find_node(filename, FHFF_NONE);
+
+ if (namenode == NULL || namenode->divert == NULL ||
+ namenode->divert->useinstead == NULL) {
+ if (opt_verbose > 0)
+ printf(_("No diversion '%s', none removed.\n"),
+ diversion_current(filename));
+ modstatdb_shutdown();
+ return 0;
+ }
+
+ if (opt_pkgname == NULL)
+ pkgset = NULL;
+ else
+ pkgset = pkg_hash_find_set(opt_pkgname);
+
+ contest = namenode->divert;
+ altname = contest->useinstead->divert;
+
+ if (opt_divertto != NULL &&
+ strcmp(opt_divertto, contest->useinstead->name) != 0)
+ ohshit(_("mismatch on divert-to\n"
+ " when removing '%s'\n"
+ " found '%s'"),
+ diversion_current(filename),
+ diversion_describe(contest));
+
+ if (!opt_pkgname_match_any && pkgset != contest->pkgset)
+ ohshit(_("mismatch on package\n"
+ " when removing '%s'\n"
+ " found '%s'"),
+ diversion_current(filename),
+ diversion_describe(contest));
+
+ /* Ignore removal request if the diverted file is still owned
+ * by another package in the same set. */
+ if (diversion_is_shared(pkgset, namenode)) {
+ if (opt_verbose > 0)
+ printf(_("Ignoring request to remove shared diversion '%s'.\n"),
+ diversion_describe(contest));
+ modstatdb_shutdown();
+ return 0;
+ }
+
+ if (opt_verbose > 0)
+ printf(_("Removing '%s'\n"), diversion_describe(contest));
+
+ file_init(&file_from, altname->camefrom->name);
+ file_init(&file_to, contest->useinstead->name);
+
+ /* Remove entries from database. */
+ contest->useinstead->divert = NULL;
+ altname->camefrom->divert = NULL;
+
+ if (opt_rename)
+ opt_rename = check_rename(&file_to, &file_from);
+ if (opt_rename && !opt_test)
+ file_rename(&file_to, &file_from);
+
+ if (!opt_test)
+ divertdb_write();
+
+ file_destroy(&file_from);
+ file_destroy(&file_to);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static int
+diversion_list(const char *const *argv)
+{
+ struct fsys_hash_iter *iter;
+ struct fsys_namenode *namenode;
+ struct glob_node *glob_list = NULL;
+ const char *pattern;
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ while ((pattern = *argv++))
+ glob_list_prepend(&glob_list, m_strdup(pattern));
+
+ if (glob_list == NULL)
+ glob_list_prepend(&glob_list, m_strdup("*"));
+
+ iter = fsys_hash_iter_new();
+ while ((namenode = fsys_hash_iter_next(iter))) {
+ struct glob_node *g;
+ struct fsys_diversion *contest = namenode->divert;
+ struct fsys_diversion *altname;
+ const char *pkgname;
+
+ if (contest == NULL || contest->useinstead == NULL)
+ continue;
+
+ altname = contest->useinstead->divert;
+
+ pkgname = diversion_pkg_name(contest);
+
+ for (g = glob_list; g; g = g->next) {
+ if (fnmatch(g->pattern, pkgname, 0) == 0 ||
+ fnmatch(g->pattern, contest->useinstead->name, 0) == 0 ||
+ fnmatch(g->pattern, altname->camefrom->name, 0) == 0) {
+ printf("%s\n", diversion_describe(contest));
+ break;
+ }
+ }
+ }
+ fsys_hash_iter_free(iter);
+
+ glob_list_free(glob_list);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static int
+diversion_truename(const char *const *argv)
+{
+ const char *filename = argv[0];
+ struct fsys_namenode *namenode;
+
+ if (!filename || argv[1])
+ badusage(_("--%s needs a single argument"), cipaction->olong);
+
+ diversion_check_filename(filename);
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ namenode = fsys_hash_find_node(filename, FHFF_NONE);
+
+ /* Print the given name if file is not diverted. */
+ if (namenode && namenode->divert && namenode->divert->useinstead)
+ printf("%s\n", namenode->divert->useinstead->name);
+ else
+ printf("%s\n", filename);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static int
+diversion_listpackage(const char *const *argv)
+{
+ const char *filename = argv[0];
+ struct fsys_namenode *namenode;
+
+ if (!filename || argv[1])
+ badusage(_("--%s needs a single argument"), cipaction->olong);
+
+ diversion_check_filename(filename);
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ namenode = fsys_hash_find_node(filename, FHFF_NONE);
+
+ /* Print nothing if file is not diverted. */
+ if (namenode == NULL || namenode->divert == NULL)
+ return 0;
+
+ if (namenode->divert->pkgset == NULL)
+ /* Indicate package is local using something not in package
+ * namespace. */
+ printf("LOCAL\n");
+ else
+ printf("%s\n", namenode->divert->pkgset->name);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static void
+set_package(const struct cmdinfo *cip, const char *value)
+{
+ opt_pkgname_match_any = false;
+
+ /* If value is NULL we are being called from --local. */
+ opt_pkgname = value;
+
+ if (opt_pkgname && strchr(opt_pkgname, '\n') != NULL)
+ badusage(_("package may not contain newlines"));
+}
+
+static void
+set_divertto(const struct cmdinfo *cip, const char *value)
+{
+ opt_divertto = value;
+
+ if (opt_divertto[0] != '/')
+ badusage(_("filename \"%s\" is not absolute"), opt_divertto);
+ if (strchr(opt_divertto, '\n') != NULL)
+ badusage(_("divert-to may not contain newlines"));
+}
+
+static const struct cmdinfo cmdinfo_add =
+ ACTION("add", 0, 0, diversion_add);
+
+static const struct cmdinfo cmdinfos[] = {
+ ACTION("add", 0, 0, diversion_add),
+ ACTION("remove", 0, 0, diversion_remove),
+ ACTION("list", 0, 0, diversion_list),
+ ACTION("listpackage", 0, 0, diversion_listpackage),
+ ACTION("truename", 0, 0, diversion_truename),
+ ACTION("help", '?', 0, usage),
+ ACTION("version", 0, 0, printversion),
+
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "instdir", 0, 1, NULL, NULL, set_instdir, 0 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "divert", 0, 1, NULL, NULL, set_divertto },
+ { "package", 0, 1, NULL, NULL, set_package },
+ { "local", 0, 0, NULL, NULL, set_package },
+ { "quiet", 0, 0, &opt_verbose, NULL, NULL, 0 },
+ { "rename", 0, 0, &opt_rename, NULL, NULL, 1 },
+ { "no-rename", 0, 0, &opt_rename, NULL, NULL, 0 },
+ { "test", 0, 0, &opt_test, NULL, NULL, 1 },
+ { NULL, 0 }
+};
+
+int
+main(int argc, const char * const *argv)
+{
+ const char *env_pkgname;
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init("dpkg-divert");
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ env_pkgname = getenv("DPKG_MAINTSCRIPT_PACKAGE");
+ if (opt_pkgname_match_any && env_pkgname)
+ set_package(NULL, env_pkgname);
+
+ if (!cipaction)
+ setaction(&cmdinfo_add, NULL);
+
+ ret = cipaction->action(argv);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return ret;
+}
diff --git a/src/dpkg-db-backup.sh b/src/dpkg-db-backup.sh
new file mode 100755
index 0000000..dbb0d6c
--- /dev/null
+++ b/src/dpkg-db-backup.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Copyright © 2014, 2017-2018, 2020-2021 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/>.
+
+PROGNAME=$(basename "$0")
+ADMINDIR=/var/lib/dpkg
+BACKUPSDIR=/var/backups
+ROTATE=7
+
+PKGDATADIR_DEFAULT=src
+PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}"
+
+# shellcheck source=src/sh/dpkg-error.sh
+. "$PKGDATADIR/sh/dpkg-error.sh"
+
+setup_colors
+
+while [ $# -ne 0 ]; do
+ case "$1" in
+ --rotate=*)
+ ROTATE="${1#--rotate=}"
+ ;;
+ esac
+ shift
+done
+
+# Check for required commands availability.
+for cmd in tar savelog; do
+ if ! command -v $cmd >/dev/null; then
+ error "cannot find required program '$cmd'"
+ fi
+done
+
+dbdir="$ADMINDIR"
+
+# Backup the N last versions of dpkg databases containing user data.
+if cd $BACKUPSDIR ; then
+ # We backup all relevant database files if any has changed, so that
+ # the rotation number always contains an internally consistent set.
+ dbchanged=no
+ dbfiles="arch status diversions statoverride"
+ for db in $dbfiles ; do
+ if ! [ -s "dpkg.${db}.0" ] && ! [ -s "$dbdir/$db" ]; then
+ # Special case the files not existing or being empty as being equal.
+ continue
+ elif ! cmp -s "dpkg.${db}.0" "$dbdir/$db"; then
+ dbchanged=yes
+ break
+ fi
+ done
+ if [ "$dbchanged" = "yes" ] ; then
+ for db in $dbfiles ; do
+ if [ -e "$dbdir/$db" ]; then
+ cp -p "$dbdir/$db" "dpkg.$db"
+ else
+ touch "dpkg.$db"
+ fi
+ savelog -c "$ROTATE" "dpkg.$db" >/dev/null
+ done
+ fi
+
+ # The alternatives database is independent from the dpkg database.
+ dbalt=alternatives
+
+ # XXX: Ideally we'd use --warning=none instead of discarding stderr, but
+ # as of GNU tar 1.27.1, it does not seem to work reliably (see #749307).
+ if ! test -e ${dbalt}.tar.0 ||
+ ! tar -df ${dbalt}.tar.0 -C $dbdir $dbalt >/dev/null 2>&1 ;
+ then
+ tar -cf ${dbalt}.tar -C $dbdir $dbalt >/dev/null 2>&1
+ savelog -c "$ROTATE" ${dbalt}.tar >/dev/null
+ fi
+fi
diff --git a/src/dpkg-maintscript-helper.sh b/src/dpkg-maintscript-helper.sh
new file mode 100755
index 0000000..d799aa8
--- /dev/null
+++ b/src/dpkg-maintscript-helper.sh
@@ -0,0 +1,667 @@
+#!/bin/sh
+#
+# Copyright © 2007, 2011-2015 Guillem Jover <guillem@debian.org>
+# Copyright © 2010 Raphaël Hertzog <hertzog@debian.org>
+# Copyright © 2008 Joey Hess <joeyh@debian.org>
+# Copyright © 2005 Scott James Remnant (original implementation on www.dpkg.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/>.
+
+# The conffile related functions are inspired by
+# https://wiki.debian.org/DpkgConffileHandling
+
+# This script is documented in dpkg-maintscript-helper(1)
+
+##
+## Functions to remove an obsolete conffile during upgrade
+##
+rm_conffile() {
+ local CONFFILE="$1"
+ local LASTVERSION="$2"
+ local PACKAGE="$3"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$PACKAGE" ] || error "couldn't identify the package"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ "${CONFFILE}" != "${CONFFILE#/}" ] || \
+ error "conffile '$CONFFILE' is not an absolute path"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 rm_conffile in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "CONFFILE=$CONFFILE PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_rm_conffile "$CONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postinst)
+ if [ "$1" = "configure" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ finish_rm_conffile "$CONFFILE"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ]; then
+ rm -f "$DPKG_ROOT$CONFFILE.dpkg-bak" \
+ "$DPKG_ROOT$CONFFILE.dpkg-remove" \
+ "$DPKG_ROOT$CONFFILE.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_rm_conffile "$CONFFILE" "$PACKAGE"
+ fi
+ ;;
+ *)
+ debug "$0 rm_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_rm_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ [ -e "$DPKG_ROOT$CONFFILE" ] || return 0
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ local md5sum old_md5sum
+ md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')"
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \
+ sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+ if [ "$md5sum" != "$old_md5sum" ]; then
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-backup"
+ else
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+finish_rm_conffile() {
+ local CONFFILE="$1"
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then
+ echo "Obsolete conffile $DPKG_ROOT$CONFFILE has been modified by you."
+ echo "Saving as $DPKG_ROOT$CONFFILE.dpkg-bak ..."
+ mv -f "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE.dpkg-bak"
+ fi
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Removing obsolete conffile $DPKG_ROOT$CONFFILE ..."
+ rm -f "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+abort_rm_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE"
+ fi
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was backed-up"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE"
+ fi
+}
+
+##
+## Functions to rename a conffile during upgrade
+##
+mv_conffile() {
+ local OLDCONFFILE="$1"
+ local NEWCONFFILE="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$PACKAGE" ] || error "couldn't identify the package"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ "${OLDCONFFILE}" != "${OLDCONFFILE#/}" ] || \
+ error "old-conffile '$OLDCONFFILE' is not an absolute path"
+ [ "${NEWCONFFILE}" != "${NEWCONFFILE#/}" ] || \
+ error "new-conffile '$NEWCONFFILE' is not an absolute path"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 mv_conffile in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "CONFFILE=$OLDCONFFILE -> $NEWCONFFILE PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_mv_conffile "$OLDCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postinst)
+ if [ "$1" = "configure" ] && [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ finish_mv_conffile "$OLDCONFFILE" "$NEWCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_mv_conffile "$OLDCONFFILE" "$PACKAGE"
+ fi
+ ;;
+ *)
+ debug "$0 mv_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_mv_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ [ -e "$DPKG_ROOT$CONFFILE" ] || return 0
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ local md5sum old_md5sum
+ md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')"
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \
+ sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+ if [ "$md5sum" = "$old_md5sum" ]; then
+ mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove"
+ fi
+}
+
+finish_mv_conffile() {
+ local OLDCONFFILE="$1"
+ local NEWCONFFILE="$2"
+ local PACKAGE="$3"
+
+ rm -f "$DPKG_ROOT$OLDCONFFILE.dpkg-remove"
+
+ [ -e "$DPKG_ROOT$OLDCONFFILE" ] || return 0
+ ensure_package_owns_file "$PACKAGE" "$OLDCONFFILE" || return 0
+
+ echo "Preserving user changes to $DPKG_ROOT$NEWCONFFILE (renamed from $DPKG_ROOT$OLDCONFFILE)..."
+ if [ -e "$DPKG_ROOT$NEWCONFFILE" ]; then
+ mv -f "$DPKG_ROOT$NEWCONFFILE" "$DPKG_ROOT$NEWCONFFILE.dpkg-new"
+ fi
+ mv -f "$DPKG_ROOT$OLDCONFFILE" "$DPKG_ROOT$NEWCONFFILE"
+}
+
+abort_mv_conffile() {
+ local CONFFILE="$1"
+ local PACKAGE="$2"
+
+ ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0
+
+ if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then
+ echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away"
+ mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE"
+ fi
+}
+
+##
+## Functions to replace a symlink with a directory
+##
+symlink_to_dir() {
+ local SYMLINK="$1"
+ local SYMLINK_TARGET="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ -n "$PACKAGE" ] || error "cannot identify the package"
+ [ -n "$SYMLINK" ] || error "symlink parameter is missing"
+ [ "${SYMLINK#/}" = "$SYMLINK" ] && \
+ error "symlink pathname is not an absolute path"
+ [ "${SYMLINK%/}" = "$SYMLINK" ] || \
+ error "symlink pathname ends with a slash"
+ [ -n "$SYMLINK_TARGET" ] || error "original symlink target is missing"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 symlink_to_dir in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "SYMLINK=$SYMLINK -> $SYMLINK_TARGET PACKAGE=$PACKAGE" \
+ "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+ [ -n "$2" ] && [ -h "$DPKG_ROOT$SYMLINK" ] &&
+ symlink_match "$SYMLINK" "$SYMLINK_TARGET" &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ mv -f "$DPKG_ROOT$SYMLINK" "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ ;;
+ postinst)
+ # We cannot bail depending on the version, as here we only
+ # know what was the last configured version, and we might
+ # have been unpacked, then upgraded with an unpack and thus
+ # never been configured before.
+ if [ "$1" = "configure" ] &&
+ [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] &&
+ symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET"
+ then
+ rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ] && [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ]; then
+ rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ [ ! -e "$DPKG_ROOT$SYMLINK" ] &&
+ [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] &&
+ symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET" &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ echo "Restoring backup of $DPKG_ROOT$SYMLINK ..."
+ mv "$DPKG_ROOT${SYMLINK}.dpkg-backup" "$DPKG_ROOT$SYMLINK"
+ fi
+ ;;
+ *)
+ debug "$0 symlink_to_dir not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+##
+## Functions to replace a directory with a symlink
+##
+dir_to_symlink() {
+ local PATHNAME="${1%/}"
+ local SYMLINK_TARGET="$2"
+ local LASTVERSION="$3"
+ local PACKAGE="$4"
+
+ if [ "$LASTVERSION" = "--" ]; then
+ LASTVERSION=""
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+ if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+ PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+ fi
+
+ # Skip remaining parameters up to --
+ while [ "$1" != "--" -a $# -gt 0 ]; do
+ shift
+ done
+ [ $# -gt 0 ] || badusage "missing arguments after --"
+ shift
+
+ [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+ [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \
+ error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required"
+ [ -n "$PACKAGE" ] || error "cannot identify the package"
+ [ -n "$PATHNAME" ] || error "directory parameter is missing"
+ [ "${PATHNAME#/}" = "$PATHNAME" ] && \
+ error "directory parameter is not an absolute path"
+ [ -n "$SYMLINK_TARGET" ] || error "new symlink target is missing"
+ [ -n "$1" ] || error "maintainer script parameters are missing"
+ validate_optional_version "$LASTVERSION"
+
+ debug "Executing $0 dir_to_symlink in $DPKG_MAINTSCRIPT_NAME" \
+ "of $DPKG_MAINTSCRIPT_PACKAGE"
+ debug "PATHNAME=$PATHNAME SYMLINK_TARGET=$SYMLINK_TARGET" \
+ "PACKAGE=$PACKAGE LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+
+ case "$DPKG_MAINTSCRIPT_NAME" in
+ preinst)
+ if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+ [ -n "$2" ] &&
+ [ ! -h "$DPKG_ROOT$PATHNAME" ] &&
+ [ -d "$DPKG_ROOT$PATHNAME" ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ prepare_dir_to_symlink "$PACKAGE" "$PATHNAME"
+ fi
+ ;;
+ postinst)
+ # We cannot bail depending on the version, as here we only
+ # know what was the last configured version, and we might
+ # have been unpacked, then upgraded with an unpack and thus
+ # never been configured before.
+ if [ "$1" = "configure" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] &&
+ [ ! -h "$DPKG_ROOT$PATHNAME" ] &&
+ [ -d "$DPKG_ROOT$PATHNAME" ] &&
+ [ -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" ]; then
+ finish_dir_to_symlink "$PATHNAME" "$SYMLINK_TARGET"
+ fi
+ ;;
+ postrm)
+ if [ "$1" = "purge" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ]; then
+ rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+ fi
+ if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+ [ -n "$2" ] &&
+ [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] &&
+ [ \( ! -h "$DPKG_ROOT$PATHNAME" -a \
+ -d "$DPKG_ROOT$PATHNAME" -a \
+ -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" \) -o \
+ \( -h "$DPKG_ROOT$PATHNAME" -a \
+ \( "$(readlink "$DPKG_ROOT$PATHNAME")" = "$SYMLINK_TARGET" -o \
+ "$(dpkg-realpath "$PATHNAME")" = "$SYMLINK_TARGET" \) \) ] &&
+ dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then
+ abort_dir_to_symlink "$PATHNAME"
+ fi
+ ;;
+ *)
+ debug "$0 dir_to_symlink not required in $DPKG_MAINTSCRIPT_NAME"
+ ;;
+ esac
+}
+
+prepare_dir_to_symlink()
+{
+ local PACKAGE="$1"
+ local PATHNAME="$2"
+
+ local LINE
+ # If there are conffiles we should not perform the switch.
+ dpkg-query -W -f='${Conffiles}\n' "$PACKAGE" | while read -r LINE; do
+ case "$LINE" in
+ "$PATHNAME"/*)
+ error "directory '$PATHNAME' contains conffiles," \
+ "cannot switch to symlink"
+ ;;
+ esac
+ done
+
+ # If there are locally created files or files owned by another package
+ # we should not perform the switch.
+ export DPKG_MAINTSCRIPT_HELPER_INTERNAL_API="$version"
+ find "$DPKG_ROOT$PATHNAME" -print0 | \
+ xargs -0 -n1 "$0" _internal_pkg_must_own_file "$PACKAGE" || \
+ error "directory '$PATHNAME' contains files not owned by" \
+ "package $PACKAGE, cannot switch to symlink"
+ unset DPKG_MAINTSCRIPT_HELPER_INTERNAL_API
+
+ # At this point, we know that the directory either contains no files,
+ # or only non-conffiles owned by the package.
+ #
+ # To do the switch we cannot simply replace it with the final symlink
+ # just yet, because dpkg needs to remove any file present in the old
+ # package that have disappeared in the new one, and we do not want to
+ # lose files resolving to the same pathname in the symlink target.
+ #
+ # We cannot replace the directory with a staging symlink either,
+ # because dpkg will update symlinks to their new target.
+ #
+ # So we need to create a staging directory, to avoid removing files
+ # from other packages, and to trap any new files in the directory
+ # to move them to their correct place later on.
+ mv -f "$DPKG_ROOT$PATHNAME" "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+ mkdir "$DPKG_ROOT$PATHNAME"
+
+ # Mark it as a staging directory, so that we can track things.
+ touch "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+}
+
+finish_dir_to_symlink()
+{
+ local PATHNAME="$1"
+ local SYMLINK_TARGET="$2"
+
+ # Move the contents of the staging directory to the symlink target,
+ # as those are all new files installed between this package being
+ # unpacked and configured.
+ local ABS_SYMLINK_TARGET
+ if [ "${SYMLINK_TARGET#/}" = "$SYMLINK_TARGET" ]; then
+ ABS_SYMLINK_TARGET="$(dirname "$PATHNAME")/$SYMLINK_TARGET"
+ else
+ ABS_SYMLINK_TARGET="$SYMLINK_TARGET"
+ fi
+ rm "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+ find "$DPKG_ROOT$PATHNAME" -mindepth 1 -maxdepth 1 -print0 | \
+ xargs -0 -I% mv -f "%" "$DPKG_ROOT$ABS_SYMLINK_TARGET/"
+
+ # Remove the staging directory.
+ rmdir "$DPKG_ROOT$PATHNAME"
+
+ # Do the actual switch.
+ ln -s "$SYMLINK_TARGET" "$DPKG_ROOT$PATHNAME"
+
+ # We are left behind the old files owned by this package in the backup
+ # directory, just remove it.
+ rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup"
+}
+
+abort_dir_to_symlink()
+{
+ local PATHNAME="$1"
+
+ echo "Restoring backup of $DPKG_ROOT$PATHNAME ..."
+ if [ -h "$DPKG_ROOT$PATHNAME" ]; then
+ rm -f "$DPKG_ROOT$PATHNAME"
+ else
+ # The staging directory must be empty, as no other package
+ # should have been unpacked in between.
+ rm -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir"
+ rmdir "$DPKG_ROOT$PATHNAME"
+ fi
+
+ mv "$DPKG_ROOT${PATHNAME}.dpkg-backup" "$DPKG_ROOT$PATHNAME"
+}
+
+# Common functions
+validate_optional_version() {
+ local VERSION="$1"
+
+ if [ -z "$VERSION" ]; then
+ return
+ fi
+
+ if ! VERSIONCHECK=$(dpkg --validate-version -- "$VERSION" 2>&1); then
+ error "$VERSIONCHECK"
+ fi
+}
+
+ensure_package_owns_file() {
+ local PACKAGE="$1"
+ local FILE="$2"
+
+ if ! dpkg-query -L "$PACKAGE" | grep -F -q -x "$FILE"; then
+ debug "File '$FILE' not owned by package " \
+ "'$PACKAGE', skipping $command"
+ return 1
+ fi
+ return 0
+}
+
+internal_pkg_must_own_file()
+{
+ local PACKAGE="$1"
+ local FILE="${2##"$DPKG_ROOT"}"
+
+ if [ "$DPKG_MAINTSCRIPT_HELPER_INTERNAL_API" != "$version" ]; then
+ error "internal API used by external command"
+ fi
+
+ if ! ensure_package_owns_file "$PACKAGE" "$FILE"; then
+ error "file '$FILE' not owned by package '$PACKAGE'"
+ fi
+ return 0
+}
+
+symlink_match()
+{
+ local SYMLINK="$1"
+ local SYMLINK_TARGET="$2"
+
+ [ "$(readlink "$DPKG_ROOT$SYMLINK")" = "$SYMLINK_TARGET" ] || \
+ [ "$(dpkg-realpath "$SYMLINK")" = "$SYMLINK_TARGET" ]
+}
+
+usage() {
+ cat <<END
+Usage: $PROGNAME <command> <parameter>... -- <maintainer-script-parameter>...
+
+Commands:
+ supports <command>
+ Returns 0 (success) if the given command is supported, 1 otherwise.
+ rm_conffile <conffile> [<last-version> [<package>]]
+ Remove obsolete conffile. Must be called in preinst, postinst and
+ postrm.
+ mv_conffile <old-conf> <new-conf> [<last-version> [<package>]]
+ Rename a conffile. Must be called in preinst, postinst and postrm.
+ symlink_to_dir <pathname> <old-symlink-target> [<last-version> [<package>]]
+ Replace a symlink with a directory. Must be called in preinst,
+ postinst and postrm.
+ dir_to_symlink <pathname> <new-symlink-target> [<last-version> [<package>]]
+ Replace a directory with a symlink. Must be called in preinst,
+ postinst and postrm.
+ help
+ -?, --help
+ Show this help message.
+ --version
+ Show the version.
+END
+}
+
+# Main code
+set -e
+
+PROGNAME=$(basename "$0")
+version="unknown"
+DPKG_ROOT=${DPKG_ROOT:+$(realpath "$DPKG_ROOT")}
+# Remove default root dir.
+if [ "$DPKG_ROOT" = "/" ]; then
+ DPKG_ROOT=""
+fi
+export DPKG_ROOT
+
+PKGDATADIR_DEFAULT=src
+PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}"
+
+# shellcheck source=src/sh/dpkg-error.sh
+. "$PKGDATADIR/sh/dpkg-error.sh"
+
+setup_colors
+
+command="$1"
+[ $# -gt 0 ] || badusage "missing command"
+shift
+
+case "$command" in
+supports)
+ case "$1" in
+ rm_conffile|mv_conffile|symlink_to_dir|dir_to_symlink)
+ code=0
+ ;;
+ *)
+ code=1
+ ;;
+ esac
+ if [ -z "$DPKG_MAINTSCRIPT_NAME" ]; then
+ warning "environment variable DPKG_MAINTSCRIPT_NAME missing"
+ code=1
+ fi
+ if [ -z "$DPKG_MAINTSCRIPT_PACKAGE" ]; then
+ warning "environment variable DPKG_MAINTSCRIPT_PACKAGE missing"
+ code=1
+ fi
+ exit $code
+ ;;
+rm_conffile)
+ rm_conffile "$@"
+ ;;
+mv_conffile)
+ mv_conffile "$@"
+ ;;
+symlink_to_dir)
+ symlink_to_dir "$@"
+ ;;
+dir_to_symlink)
+ dir_to_symlink "$@"
+ ;;
+_internal_pkg_must_own_file)
+ # This is an internal command, must not be used outside this program.
+ internal_pkg_must_own_file "$@"
+ ;;
+--help|help|-?)
+ usage
+ ;;
+--version)
+ cat <<END
+Debian $PROGNAME version $version.
+
+This is free software; see the GNU General Public License version 2 or
+later for copying conditions. There is NO warranty.
+END
+ ;;
+*)
+ badusage "command $command is unknown
+Hint: upgrading dpkg to a newer version might help."
+esac
+
+exit 0
diff --git a/src/dpkg-realpath.sh b/src/dpkg-realpath.sh
new file mode 100755
index 0000000..84438b4
--- /dev/null
+++ b/src/dpkg-realpath.sh
@@ -0,0 +1,179 @@
+#!/bin/sh
+#
+# Copyright © 2020 Helmut Grohne <helmut@subdivi.de>
+# Copyright © 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/>.
+
+set -e
+
+PROGNAME=$(basename "$0")
+version="unknown"
+EOL="\n"
+
+PKGDATADIR_DEFAULT=src
+PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}"
+
+# shellcheck source=src/sh/dpkg-error.sh
+. "$PKGDATADIR/sh/dpkg-error.sh"
+
+show_version()
+{
+ cat <<END
+Debian $PROGNAME version $version.
+
+This is free software; see the GNU General Public License version 2 or
+later for copying conditions. There is NO warranty.
+END
+}
+
+show_usage()
+{
+ cat <<END
+Usage: $PROGNAME [<option>...] <pathname>
+
+Options:
+ -z, --zero end output line with NUL, not newline.
+ --instdir <directory> set the root directory.
+ --root <directory> set the root directory.
+ --version show the version.
+ -?, --help show this help message.
+END
+}
+
+canonicalize() {
+ local src="$1"
+ local root="$DPKG_ROOT"
+ local loop=0
+ local result="$root"
+ local dst
+
+ # Check whether the path is relative and make it absolute otherwise.
+ if [ "$src" = "${src#/}" ]; then
+ src="$(pwd)/$src"
+ src="${src#"$root"}"
+ fi
+
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ while [ -n "$src" ]; do
+ # Get the first directory component.
+ prefix=${src%%/*}
+ # Remove the first directory component from src.
+ src=${src#"$prefix"}
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ # Resolve the first directory component.
+ if [ "$prefix" = . ]; then
+ # Ignore, stay at the same directory.
+ :
+ elif [ "$prefix" = .. ]; then
+ # Go up one directory.
+ result=${result%/*}
+ if [ -n "$root" ] && [ "${result#"$root"}" = "$result" ]; then
+ result="$root"
+ fi
+ elif [ -h "$result/$prefix" ]; then
+ loop=$((loop + 1))
+ if [ "$loop" -gt 25 ]; then
+ error "too many levels of symbolic links"
+ fi
+ # Resolve the symlink within $result.
+ dst=$(readlink "$result/$prefix")
+ case "$dst" in
+ /*)
+ # Absolute pathname, reset result back to $root.
+ result=$root
+ src="$dst${src:+/$src}"
+ # Remove prefixed slashes.
+ while [ "$src" != "${src#/}" ]; do
+ src=${src#/}
+ done
+ ;;
+ *)
+ # Relative pathname.
+ src="$dst${src:+/$src}"
+ ;;
+ esac
+ else
+ # Otherwise append the prefix.
+ result="$result/$prefix"
+ fi
+ done
+ # We are done, print the resolved pathname, w/o $root.
+ result="${result#"$root"}"
+ printf "%s$EOL" "${result:-/}"
+}
+
+setup_colors
+
+DPKG_ROOT="${DPKG_ROOT:-}"
+export DPKG_ROOT
+
+while [ $# -ne 0 ]; do
+ case "$1" in
+ -z|--zero)
+ EOL="\0"
+ ;;
+ --instdir|--root)
+ shift
+ DPKG_ROOT=$1
+ ;;
+ --instdir=*)
+ DPKG_ROOT="${1#--instdir=}"
+ ;;
+ --root=*)
+ DPKG_ROOT="${1#--root=}"
+ ;;
+ --version)
+ show_version
+ exit 0
+ ;;
+ --help|-\?)
+ show_usage
+ exit 0
+ ;;
+ --)
+ shift
+ pathname="$1"
+ ;;
+ -*)
+ badusage "unknown option: $1"
+ ;;
+ *)
+ pathname="$1"
+ ;;
+ esac
+ shift
+done
+
+# Normalize root directory.
+DPKG_ROOT="${DPKG_ROOT:+$(realpath "$DPKG_ROOT")}"
+# Remove default root dir.
+if [ "$DPKG_ROOT" = "/" ]; then
+ DPKG_ROOT=""
+fi
+
+[ -n "$pathname" ] || badusage "missing pathname"
+if [ "${pathname#"$DPKG_ROOT"}" != "$pathname" ]; then
+ error "link '$pathname' includes root prefix '$DPKG_ROOT'"
+fi
+
+canonicalize "$pathname"
+
+exit 0
diff --git a/src/main/archives.c b/src/main/archives.c
new file mode 100644
index 0000000..5618c1a
--- /dev/null
+++ b/src/main/archives.c
@@ -0,0 +1,1703 @@
+/*
+ * dpkg - main program for package management
+ * archives.c - actions that process archive files, mainly unpack
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2000 Wichert Akkerman <wakkerma@debian.org>
+ * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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/time.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <obstack.h>
+#define obstack_chunk_alloc m_malloc
+#define obstack_chunk_free free
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/pkg.h>
+#include <dpkg/path.h>
+#include <dpkg/fdio.h>
+#include <dpkg/buffer.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/file.h>
+#include <dpkg/treewalk.h>
+#include <dpkg/tarfn.h>
+#include <dpkg/options.h>
+#include <dpkg/triglib.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+#include "archives.h"
+#include "filters.h"
+
+static inline void
+fd_writeback_init(int fd)
+{
+ /* Ignore the return code as it should be considered equivalent to an
+ * asynchronous hint for the kernel, we are doing an fsync() later on
+ * anyway. */
+#if defined(SYNC_FILE_RANGE_WRITE)
+ sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
+#elif defined(HAVE_POSIX_FADVISE)
+ posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
+#endif
+}
+
+static struct obstack tar_pool;
+static bool tar_pool_init = false;
+
+/**
+ * Allocate memory from the tar memory pool.
+ */
+static void *
+tar_pool_alloc(size_t size)
+{
+ if (!tar_pool_init) {
+ obstack_init(&tar_pool);
+ tar_pool_init = true;
+ }
+
+ return obstack_alloc(&tar_pool, size);
+}
+
+/**
+ * Free memory from the tar memory pool.
+ */
+static void
+tar_pool_free(void *ptr)
+{
+ obstack_free(&tar_pool, ptr);
+}
+
+/**
+ * Release the tar memory pool.
+ */
+static void
+tar_pool_release(void)
+{
+ if (tar_pool_init) {
+ obstack_free(&tar_pool, NULL);
+ tar_pool_init = false;
+ }
+}
+
+struct fsys_namenode_list *
+tar_fsys_namenode_queue_push(struct fsys_namenode_queue *queue,
+ struct fsys_namenode *namenode)
+{
+ struct fsys_namenode_list *node;
+
+ node = tar_pool_alloc(sizeof(*node));
+ node->namenode = namenode;
+ node->next = NULL;
+
+ *queue->tail = node;
+ queue->tail = &node->next;
+
+ return node;
+}
+
+static void
+tar_fsys_namenode_queue_pop(struct fsys_namenode_queue *queue,
+ struct fsys_namenode_list **tail_prev,
+ struct fsys_namenode_list *node)
+{
+ tar_pool_free(node);
+ queue->tail = tail_prev;
+ *tail_prev = NULL;
+}
+
+/**
+ * Check if a file or directory will save a package from disappearance.
+ *
+ * A package can only be saved by a file or directory which is part
+ * only of itself - it must be neither part of the new package being
+ * installed nor part of any 3rd package (this is important so that
+ * shared directories don't stop packages from disappearing).
+ */
+bool
+filesavespackage(struct fsys_namenode_list *file,
+ struct pkginfo *pkgtobesaved,
+ struct pkginfo *pkgbeinginstalled)
+{
+ struct fsys_node_pkgs_iter *iter;
+ struct pkgset *divpkgset;
+ struct pkginfo *thirdpkg;
+
+ debug(dbg_eachfiledetail, "filesavespackage file '%s' package %s",
+ file->namenode->name, pkg_name(pkgtobesaved, pnaw_always));
+
+ /* If the file is a contended one and it's overridden by either
+ * the package we're considering disappearing or the package
+ * we're installing then they're not actually the same file, so
+ * we can't disappear the package - it is saved by this file. */
+ if (file->namenode->divert && file->namenode->divert->useinstead) {
+ divpkgset = file->namenode->divert->pkgset;
+ if (divpkgset == pkgtobesaved->set || divpkgset == pkgbeinginstalled->set) {
+ debug(dbg_eachfiledetail,"filesavespackage ... diverted -- save!");
+ return true;
+ }
+ }
+ /* Is the file in the package being installed? If so then it can't save. */
+ if (file->namenode->flags & FNNF_NEW_INARCHIVE) {
+ debug(dbg_eachfiledetail,"filesavespackage ... in new archive -- no save");
+ return false;
+ }
+ /* Look for a 3rd package which can take over the file (in case
+ * it's a directory which is shared by many packages. */
+ iter = fsys_node_pkgs_iter_new(file->namenode);
+ while ((thirdpkg = fsys_node_pkgs_iter_next(iter))) {
+ debug(dbg_eachfiledetail, "filesavespackage ... also in %s",
+ pkg_name(thirdpkg, pnaw_always));
+
+ /* Is this not the package being installed or the one being
+ * checked for disappearance? */
+ if (thirdpkg == pkgbeinginstalled || thirdpkg == pkgtobesaved)
+ continue;
+
+ /* A Multi-Arch: same package can share files and their presence in a
+ * third package of the same set is not a sign that we can get rid of
+ * it. */
+ if (pkgtobesaved->installed.multiarch == PKG_MULTIARCH_SAME &&
+ thirdpkg->set == pkgtobesaved->set)
+ continue;
+
+ /* If !fileslistvalid then we've already disappeared this one, so
+ * we shouldn't try to make it take over this shared directory. */
+ debug(dbg_eachfiledetail,"filesavespackage ... is 3rd package");
+
+ if (!thirdpkg->files_list_valid) {
+ debug(dbg_eachfiledetail, "process_archive ... already disappeared!");
+ continue;
+ }
+
+ /* We've found a package that can take this file. */
+ debug(dbg_eachfiledetail, "filesavespackage ... taken -- no save");
+ fsys_node_pkgs_iter_free(iter);
+ return false;
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ debug(dbg_eachfiledetail, "filesavespackage ... not taken -- save !");
+ return true;
+}
+
+static void
+md5hash_prev_conffile(struct pkginfo *pkg, char *oldhash, const char *oldname,
+ struct fsys_namenode *namenode)
+{
+ struct pkginfo *otherpkg;
+ struct conffile *conff;
+
+ debug(dbg_conffdetail, "tarobject looking for shared conffile %s",
+ namenode->name);
+
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ /* If we are reinstalling, even if the other package is only unpacked,
+ * we can always make use of the Conffiles hash value from an initial
+ * installation, if that happened at all. */
+ if (otherpkg->status <= PKG_STAT_UNPACKED &&
+ dpkg_version_compare(&otherpkg->installed.version,
+ &otherpkg->configversion) != 0)
+ continue;
+ for (conff = otherpkg->installed.conffiles; conff; conff = conff->next) {
+ if (conff->obsolete || conff->remove_on_upgrade)
+ continue;
+ if (strcmp(conff->name, namenode->name) == 0)
+ break;
+ }
+ if (conff) {
+ strcpy(oldhash, conff->hash);
+ debug(dbg_conffdetail,
+ "tarobject found shared conffile, from pkg %s (%s); digest=%s",
+ pkg_name(otherpkg, pnaw_always),
+ pkg_status_name(otherpkg), oldhash);
+ break;
+ }
+ }
+
+ /* If no package was found with a valid Conffiles field, we make the
+ * risky assumption that the hash of the current .dpkg-new file is
+ * the one of the previously unpacked package. */
+ if (otherpkg == NULL) {
+ md5hash(pkg, oldhash, oldname);
+ debug(dbg_conffdetail,
+ "tarobject found shared conffile, from disk; digest=%s", oldhash);
+ }
+}
+
+void cu_pathname(int argc, void **argv) {
+ path_remove_tree((char*)(argv[0]));
+}
+
+int
+tarfileread(struct tar_archive *tar, char *buf, int len)
+{
+ struct tarcontext *tc = (struct tarcontext *)tar->ctx;
+ int r;
+
+ r = fd_read(tc->backendpipe, buf, len);
+ if (r < 0)
+ ohshite(_("error reading from dpkg-deb pipe"));
+ return r;
+}
+
+static void
+tarobject_skip_padding(struct tarcontext *tc, struct tar_entry *te)
+{
+ struct dpkg_error err;
+ size_t remainder;
+
+ remainder = te->size % TARBLKSZ;
+ if (remainder == 0)
+ return;
+
+ if (fd_skip(tc->backendpipe, TARBLKSZ - remainder, &err) < 0)
+ ohshit(_("cannot skip padding for file '%.255s': %s"), te->name, err.str);
+}
+
+static void
+tarobject_skip_entry(struct tarcontext *tc, struct tar_entry *ti)
+{
+ /* We need to advance the tar file to the next object, so read the
+ * file data and set it to oblivion. */
+ if (ti->type == TAR_FILETYPE_FILE) {
+ struct dpkg_error err;
+ char fnamebuf[256];
+
+ if (fd_skip(tc->backendpipe, ti->size, &err) < 0)
+ ohshit(_("cannot skip file '%.255s' (replaced or excluded?) from pipe: %s"),
+ path_quote_filename(fnamebuf, ti->name, 256), err.str);
+ tarobject_skip_padding(tc, ti);
+ }
+}
+
+struct varbuf_state fname_state;
+struct varbuf_state fnametmp_state;
+struct varbuf_state fnamenew_state;
+struct varbuf fnamevb;
+struct varbuf fnametmpvb;
+struct varbuf fnamenewvb;
+struct pkg_deconf_list *deconfigure = NULL;
+
+static time_t currenttime;
+
+static int
+does_replace(struct pkginfo *new_pkg, struct pkgbin *new_pkgbin,
+ struct pkginfo *old_pkg, struct pkgbin *old_pkgbin)
+{
+ struct dependency *dep;
+
+ debug(dbg_depcon,"does_replace new=%s old=%s (%s)",
+ pkgbin_name(new_pkg, new_pkgbin, pnaw_always),
+ pkgbin_name(old_pkg, old_pkgbin, pnaw_always),
+ versiondescribe_c(&old_pkgbin->version, vdew_always));
+ for (dep = new_pkgbin->depends; dep; dep = dep->next) {
+ if (dep->type != dep_replaces || dep->list->ed != old_pkg->set)
+ continue;
+ debug(dbg_depcondetail,"does_replace ... found old, version %s",
+ versiondescribe_c(&dep->list->version,vdew_always));
+ if (!versionsatisfied(old_pkgbin, dep->list))
+ continue;
+ /* The test below can only trigger if dep_replaces start having
+ * arch qualifiers different from “any”. */
+ if (!archsatisfied(old_pkgbin, dep->list))
+ continue;
+ debug(dbg_depcon,"does_replace ... yes");
+ return true;
+ }
+ debug(dbg_depcon,"does_replace ... no");
+ return false;
+}
+
+static void
+tarobject_extract(struct tarcontext *tc, struct tar_entry *te,
+ const char *path, struct file_stat *st,
+ struct fsys_namenode *namenode)
+{
+ static struct varbuf hardlinkfn;
+ static int fd;
+
+ struct dpkg_error err;
+ struct fsys_namenode *linknode;
+ char fnamebuf[256];
+ char fnamenewbuf[256];
+ char *newhash;
+ int rc;
+
+ switch (te->type) {
+ case TAR_FILETYPE_FILE:
+ /* We create the file with mode 0 to make sure nobody can do anything with
+ * it until we apply the proper mode, which might be a statoverride. */
+ fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0);
+ if (fd < 0)
+ ohshite(_("unable to create '%.255s' (while processing '%.255s')"),
+ path, te->name);
+ push_cleanup(cu_closefd, ehflag_bombout, 1, &fd);
+ debug(dbg_eachfiledetail, "tarobject file open size=%jd",
+ (intmax_t)te->size);
+
+ /* We try to tell the filesystem how much disk space we are going to
+ * need to let it reduce fragmentation and possibly improve performance,
+ * as we do know the size beforehand. */
+ fd_allocate_size(fd, 0, te->size);
+
+ newhash = nfmalloc(MD5HASHLEN + 1);
+ if (fd_fd_copy_and_md5(tc->backendpipe, fd, newhash, te->size, &err) < 0)
+ ohshit(_("cannot copy extracted data for '%.255s' to '%.255s': %s"),
+ path_quote_filename(fnamebuf, te->name, 256),
+ path_quote_filename(fnamenewbuf, fnamenewvb.buf, 256), err.str);
+ namenode->newhash = newhash;
+ debug(dbg_eachfiledetail, "tarobject file digest=%s", namenode->newhash);
+
+ tarobject_skip_padding(tc, te);
+
+ fd_writeback_init(fd);
+
+ if (namenode->statoverride)
+ debug(dbg_eachfile, "tarobject ... stat override, uid=%d, gid=%d, mode=%04o",
+ namenode->statoverride->uid,
+ namenode->statoverride->gid,
+ namenode->statoverride->mode);
+ rc = fchown(fd, st->uid, st->gid);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("error setting ownership of '%.255s'"), te->name);
+ rc = fchmod(fd, st->mode & ~S_IFMT);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("error setting permissions of '%.255s'"), te->name);
+
+ /* Postpone the fsync, to try to avoid massive I/O degradation. */
+ if (!in_force(FORCE_UNSAFE_IO))
+ namenode->flags |= FNNF_DEFERRED_FSYNC;
+
+ pop_cleanup(ehflag_normaltidy); /* fd = open(path) */
+ if (close(fd))
+ ohshite(_("error closing/writing '%.255s'"), te->name);
+ break;
+ case TAR_FILETYPE_FIFO:
+ if (mkfifo(path, 0))
+ ohshite(_("error creating pipe '%.255s'"), te->name);
+ debug(dbg_eachfiledetail, "tarobject fifo");
+ break;
+ case TAR_FILETYPE_CHARDEV:
+ if (mknod(path, S_IFCHR, te->dev))
+ ohshite(_("error creating device '%.255s'"), te->name);
+ debug(dbg_eachfiledetail, "tarobject chardev");
+ break;
+ case TAR_FILETYPE_BLOCKDEV:
+ if (mknod(path, S_IFBLK, te->dev))
+ ohshite(_("error creating device '%.255s'"), te->name);
+ debug(dbg_eachfiledetail, "tarobject blockdev");
+ break;
+ case TAR_FILETYPE_HARDLINK:
+ varbuf_reset(&hardlinkfn);
+ varbuf_add_str(&hardlinkfn, dpkg_fsys_get_dir());
+ linknode = fsys_hash_find_node(te->linkname, 0);
+ varbuf_add_str(&hardlinkfn,
+ namenodetouse(linknode, tc->pkg, &tc->pkg->available)->name);
+ if (linknode->flags & (FNNF_DEFERRED_RENAME | FNNF_NEW_CONFF))
+ varbuf_add_str(&hardlinkfn, DPKGNEWEXT);
+ varbuf_end_str(&hardlinkfn);
+ if (link(hardlinkfn.buf, path))
+ ohshite(_("error creating hard link '%.255s'"), te->name);
+ namenode->newhash = linknode->newhash;
+ debug(dbg_eachfiledetail, "tarobject hardlink digest=%s", namenode->newhash);
+ break;
+ case TAR_FILETYPE_SYMLINK:
+ /* We've already checked for an existing directory. */
+ if (symlink(te->linkname, path))
+ ohshite(_("error creating symbolic link '%.255s'"), te->name);
+ debug(dbg_eachfiledetail, "tarobject symlink creating");
+ break;
+ case TAR_FILETYPE_DIR:
+ /* We've already checked for an existing directory. */
+ if (mkdir(path, 0))
+ ohshite(_("error creating directory '%.255s'"), te->name);
+ debug(dbg_eachfiledetail, "tarobject directory creating");
+ break;
+ default:
+ internerr("unknown tar type '%d', but already checked", te->type);
+ }
+}
+
+static void
+tarobject_hash(struct tarcontext *tc, struct tar_entry *te,
+ struct fsys_namenode *namenode)
+{
+ if (te->type == TAR_FILETYPE_FILE) {
+ struct dpkg_error err;
+ char fnamebuf[256];
+ char *newhash;
+
+ newhash = nfmalloc(MD5HASHLEN + 1);
+ if (fd_md5(tc->backendpipe, newhash, te->size, &err) < 0)
+ ohshit(_("cannot compute MD5 digest for file '%.255s' in tar archive: %s"),
+ path_quote_filename(fnamebuf, te->name, 256), err.str);
+ tarobject_skip_padding(tc, te);
+
+ namenode->newhash = newhash;
+ debug(dbg_eachfiledetail, "tarobject file digest=%s", namenode->newhash);
+ } else if (te->type == TAR_FILETYPE_HARDLINK) {
+ struct fsys_namenode *linknode;
+
+ linknode = fsys_hash_find_node(te->linkname, 0);
+ namenode->newhash = linknode->newhash;
+ debug(dbg_eachfiledetail, "tarobject hardlink digest=%s", namenode->newhash);
+ }
+}
+
+static void
+tarobject_set_mtime(struct tar_entry *te, const char *path)
+{
+ struct timeval tv[2];
+
+ tv[0].tv_sec = currenttime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = te->mtime;
+ tv[1].tv_usec = 0;
+
+ if (te->type == TAR_FILETYPE_SYMLINK) {
+#ifdef HAVE_LUTIMES
+ if (lutimes(path, tv) && errno != ENOSYS)
+ ohshite(_("error setting timestamps of '%.255s'"), path);
+#endif
+ } else {
+ if (utimes(path, tv))
+ ohshite(_("error setting timestamps of '%.255s'"), path);
+ }
+}
+
+static void
+tarobject_set_perms(struct tar_entry *te, const char *path, struct file_stat *st)
+{
+ int rc;
+
+ if (te->type == TAR_FILETYPE_FILE)
+ return; /* Already handled using the file descriptor. */
+
+ if (te->type == TAR_FILETYPE_SYMLINK) {
+ rc = lchown(path, st->uid, st->gid);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("error setting ownership of symlink '%.255s'"), path);
+ } else {
+ rc = chown(path, st->uid, st->gid);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("error setting ownership of '%.255s'"), path);
+ rc = chmod(path, st->mode & ~S_IFMT);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("error setting permissions of '%.255s'"), path);
+ }
+}
+
+static void
+tarobject_set_se_context(const char *matchpath, const char *path, mode_t mode)
+{
+ dpkg_selabel_set_context(matchpath, path, mode);
+}
+
+static void
+tarobject_matches(struct tarcontext *tc,
+ const char *fn_old, struct stat *stab, char *oldhash,
+ const char *fn_new, struct tar_entry *te,
+ struct fsys_namenode *namenode)
+{
+ char *linkname;
+ ssize_t linksize;
+
+ debug(dbg_eachfiledetail, "tarobject matches on-disk object?");
+
+ switch (te->type) {
+ case TAR_FILETYPE_DIR:
+ /* Nothing to check for a new directory. */
+ return;
+ case TAR_FILETYPE_SYMLINK:
+ /* Symlinks to existing dirs have already been dealt with, only
+ * remain real symlinks where we can compare the target. */
+ if (!S_ISLNK(stab->st_mode))
+ break;
+ linkname = m_malloc(stab->st_size + 1);
+ linksize = readlink(fn_old, linkname, stab->st_size + 1);
+ if (linksize < 0)
+ ohshite(_("unable to read link '%.255s'"), fn_old);
+ else if (linksize > stab->st_size)
+ ohshit(_("symbolic link '%.250s' size has changed from %jd to %zd"),
+ fn_old, (intmax_t)stab->st_size, linksize);
+ else if (linksize < stab->st_size)
+ warning(_("symbolic link '%.250s' size has changed from %jd to %zd"),
+ fn_old, (intmax_t)stab->st_size, linksize);
+ linkname[linksize] = '\0';
+ if (strcmp(linkname, te->linkname) == 0) {
+ free(linkname);
+ return;
+ } else {
+ free(linkname);
+ }
+ break;
+ case TAR_FILETYPE_CHARDEV:
+ if (S_ISCHR(stab->st_mode) && stab->st_rdev == te->dev)
+ return;
+ break;
+ case TAR_FILETYPE_BLOCKDEV:
+ if (S_ISBLK(stab->st_mode) && stab->st_rdev == te->dev)
+ return;
+ break;
+ case TAR_FILETYPE_FIFO:
+ if (S_ISFIFO(stab->st_mode))
+ return;
+ break;
+ case TAR_FILETYPE_HARDLINK:
+ /* Fall through. */
+ case TAR_FILETYPE_FILE:
+ /* Only check metadata for non-conffiles. */
+ if (!(namenode->flags & FNNF_NEW_CONFF) &&
+ !(S_ISREG(stab->st_mode) && te->size == stab->st_size))
+ break;
+ if (strcmp(oldhash, namenode->newhash) == 0)
+ return;
+ break;
+ default:
+ internerr("unknown tar type '%d', but already checked", te->type);
+ }
+
+ forcibleerr(FORCE_OVERWRITE,
+ _("trying to overwrite shared '%.250s', which is different "
+ "from other instances of package %.250s"),
+ namenode->name, pkg_name(tc->pkg, pnaw_nonambig));
+}
+
+void setupfnamevbs(const char *filename) {
+ varbuf_rollback(&fname_state);
+ varbuf_add_str(&fnamevb, filename);
+ varbuf_end_str(&fnamevb);
+
+ varbuf_rollback(&fnametmp_state);
+ varbuf_add_str(&fnametmpvb, filename);
+ varbuf_add_str(&fnametmpvb, DPKGTEMPEXT);
+ varbuf_end_str(&fnametmpvb);
+
+ varbuf_rollback(&fnamenew_state);
+ varbuf_add_str(&fnamenewvb, filename);
+ varbuf_add_str(&fnamenewvb, DPKGNEWEXT);
+ varbuf_end_str(&fnamenewvb);
+
+ debug(dbg_eachfiledetail, "setupvnamevbs main='%s' tmp='%s' new='%s'",
+ fnamevb.buf, fnametmpvb.buf, fnamenewvb.buf);
+}
+
+static bool
+linktosameexistingdir(const struct tar_entry *ti, const char *fname,
+ struct varbuf *symlinkfn)
+{
+ struct stat oldstab, newstab;
+ int statr;
+ const char *lastslash;
+
+ statr= stat(fname, &oldstab);
+ if (statr) {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ ohshite(_("failed to stat (dereference) existing symlink '%.250s'"),
+ fname);
+ return false;
+ }
+ if (!S_ISDIR(oldstab.st_mode))
+ return false;
+
+ /* But is it to the same dir? */
+ varbuf_reset(symlinkfn);
+ if (ti->linkname[0] == '/') {
+ varbuf_add_str(symlinkfn, dpkg_fsys_get_dir());
+ } else {
+ lastslash= strrchr(fname, '/');
+ if (lastslash == NULL)
+ internerr("tar entry filename '%s' does not contain '/'", fname);
+ varbuf_add_buf(symlinkfn, fname, (lastslash - fname) + 1);
+ }
+ varbuf_add_str(symlinkfn, ti->linkname);
+ varbuf_end_str(symlinkfn);
+
+ statr= stat(symlinkfn->buf, &newstab);
+ if (statr) {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ ohshite(_("failed to stat (dereference) proposed new symlink target"
+ " '%.250s' for symlink '%.250s'"), symlinkfn->buf, fname);
+ return false;
+ }
+ if (!S_ISDIR(newstab.st_mode))
+ return false;
+ if (newstab.st_dev != oldstab.st_dev ||
+ newstab.st_ino != oldstab.st_ino)
+ return false;
+ return true;
+}
+
+int
+tarobject(struct tar_archive *tar, struct tar_entry *ti)
+{
+ static struct varbuf conffderefn, symlinkfn;
+ const char *usename;
+ struct fsys_namenode *namenode, *usenode;
+
+ struct conffile *conff;
+ struct tarcontext *tc = tar->ctx;
+ bool existingdir, keepexisting;
+ bool refcounting;
+ char oldhash[MD5HASHLEN + 1];
+ int statr;
+ ssize_t r;
+ struct stat stab, stabtmp;
+ struct file_stat nodestat;
+ struct fsys_namenode_list *nifd, **oldnifd;
+ struct pkgset *divpkgset;
+ struct pkginfo *otherpkg;
+
+ tar_entry_update_from_system(ti);
+
+ /* Perform some sanity checks on the tar entry. */
+ if (strchr(ti->name, '\n'))
+ ohshit(_("newline not allowed in archive object name '%.255s'"), ti->name);
+
+ namenode = fsys_hash_find_node(ti->name, 0);
+
+ if (namenode->flags & FNNF_RM_CONFF_ON_UPGRADE)
+ ohshit(_("conffile '%s' marked for removal on upgrade, shipped in package"),
+ ti->name);
+
+ /* Append to list of files.
+ * The trailing ‘/’ put on the end of names in tarfiles has already
+ * been stripped by tar_extractor(). */
+ oldnifd = tc->newfiles_queue->tail;
+ nifd = tar_fsys_namenode_queue_push(tc->newfiles_queue, namenode);
+ nifd->namenode->flags |= FNNF_NEW_INARCHIVE;
+
+ debug(dbg_eachfile,
+ "tarobject ti->name='%s' mode=%lo owner=%u:%u type=%d(%c)"
+ " ti->linkname='%s' namenode='%s' flags=%o instead='%s'",
+ ti->name, (long)ti->stat.mode,
+ (unsigned)ti->stat.uid, (unsigned)ti->stat.gid,
+ ti->type,
+ ti->type >= '0' && ti->type <= '6' ? "-hlcbdp"[ti->type - '0'] : '?',
+ ti->linkname,
+ nifd->namenode->name, nifd->namenode->flags,
+ nifd->namenode->divert && nifd->namenode->divert->useinstead
+ ? nifd->namenode->divert->useinstead->name : "<none>");
+
+ if (nifd->namenode->divert && nifd->namenode->divert->camefrom) {
+ divpkgset = nifd->namenode->divert->pkgset;
+
+ if (divpkgset) {
+ forcibleerr(FORCE_OVERWRITE_DIVERTED,
+ _("trying to overwrite '%.250s', which is the "
+ "diverted version of '%.250s' (package: %.100s)"),
+ nifd->namenode->name, nifd->namenode->divert->camefrom->name,
+ divpkgset->name);
+ } else {
+ forcibleerr(FORCE_OVERWRITE_DIVERTED,
+ _("trying to overwrite '%.250s', which is the "
+ "diverted version of '%.250s'"),
+ nifd->namenode->name, nifd->namenode->divert->camefrom->name);
+ }
+ }
+
+ if (nifd->namenode->statoverride) {
+ nodestat = *nifd->namenode->statoverride;
+ nodestat.mode |= ti->stat.mode & S_IFMT;
+ } else {
+ nodestat = ti->stat;
+ }
+
+ usenode = namenodetouse(nifd->namenode, tc->pkg, &tc->pkg->available);
+ usename = usenode->name;
+
+ trig_file_activate(usenode, tc->pkg);
+
+ if (nifd->namenode->flags & FNNF_NEW_CONFF) {
+ /* If it's a conffile we have to extract it next to the installed
+ * version (i.e. we do the usual link-following). */
+ if (conffderef(tc->pkg, &conffderefn, usename))
+ usename= conffderefn.buf;
+ debug(dbg_conff, "tarobject FNNF_NEW_CONFF deref='%s'", usename);
+ }
+
+ setupfnamevbs(usename);
+
+ statr= lstat(fnamevb.buf,&stab);
+ if (statr) {
+ /* The lstat failed. */
+ if (errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to stat '%.255s' (which was about to be installed)"),
+ ti->name);
+ /* OK, so it doesn't exist.
+ * However, it's possible that we were in the middle of some other
+ * backup/restore operation and were rudely interrupted.
+ * So, we see if we have .dpkg-tmp, and if so we restore it. */
+ if (rename(fnametmpvb.buf,fnamevb.buf)) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to clean up mess surrounding '%.255s' before "
+ "installing another version"), ti->name);
+ debug(dbg_eachfiledetail,"tarobject nonexistent");
+ } else {
+ debug(dbg_eachfiledetail,"tarobject restored tmp to main");
+ statr= lstat(fnamevb.buf,&stab);
+ if (statr)
+ ohshite(_("unable to stat restored '%.255s' before installing"
+ " another version"), ti->name);
+ }
+ } else {
+ debug(dbg_eachfiledetail,"tarobject already exists");
+ }
+
+ /* Check to see if it's a directory or link to one and we don't need to
+ * do anything. This has to be done now so that we don't die due to
+ * a file overwriting conflict. */
+ existingdir = false;
+ switch (ti->type) {
+ case TAR_FILETYPE_SYMLINK:
+ /* If it's already an existing directory, do nothing. */
+ if (!statr && S_ISDIR(stab.st_mode)) {
+ debug(dbg_eachfiledetail, "tarobject symlink exists as directory");
+ existingdir = true;
+ } else if (!statr && S_ISLNK(stab.st_mode)) {
+ if (linktosameexistingdir(ti, fnamevb.buf, &symlinkfn))
+ existingdir = true;
+ }
+ break;
+ case TAR_FILETYPE_DIR:
+ /* If it's already an existing directory, do nothing. */
+ if (!stat(fnamevb.buf,&stabtmp) && S_ISDIR(stabtmp.st_mode)) {
+ debug(dbg_eachfiledetail, "tarobject directory exists");
+ existingdir = true;
+ }
+ break;
+ case TAR_FILETYPE_FILE:
+ case TAR_FILETYPE_CHARDEV:
+ case TAR_FILETYPE_BLOCKDEV:
+ case TAR_FILETYPE_FIFO:
+ case TAR_FILETYPE_HARDLINK:
+ break;
+ default:
+ ohshit(_("archive contained object '%.255s' of unknown type 0x%x"),
+ ti->name, ti->type);
+ }
+
+ keepexisting = false;
+ refcounting = false;
+ if (!existingdir) {
+ struct fsys_node_pkgs_iter *iter;
+
+ iter = fsys_node_pkgs_iter_new(nifd->namenode);
+ while ((otherpkg = fsys_node_pkgs_iter_next(iter))) {
+ if (otherpkg == tc->pkg)
+ continue;
+ debug(dbg_eachfile, "tarobject ... found in %s",
+ pkg_name(otherpkg, pnaw_always));
+
+ /* A pkgset can share files between its instances. Overwriting
+ * is allowed when they are not getting in sync, otherwise the
+ * file content must match the installed file. */
+ if (otherpkg->set == tc->pkg->set &&
+ otherpkg->installed.multiarch == PKG_MULTIARCH_SAME &&
+ tc->pkg->available.multiarch == PKG_MULTIARCH_SAME) {
+ if (statr == 0 && tc->pkgset_getting_in_sync)
+ refcounting = true;
+ debug(dbg_eachfiledetail, "tarobject ... shared with %s %s (syncing=%d)",
+ pkg_name(otherpkg, pnaw_always),
+ versiondescribe_c(&otherpkg->installed.version, vdew_nonambig),
+ tc->pkgset_getting_in_sync);
+ continue;
+ }
+
+ if (nifd->namenode->divert && nifd->namenode->divert->useinstead) {
+ /* Right, so we may be diverting this file. This makes the conflict
+ * OK iff one of us is the diverting package (we don't need to
+ * check for both being the diverting package, obviously). */
+ divpkgset = nifd->namenode->divert->pkgset;
+ debug(dbg_eachfile, "tarobject ... diverted, divpkgset=%s",
+ divpkgset ? divpkgset->name : "<none>");
+ if (otherpkg->set == divpkgset || tc->pkg->set == divpkgset)
+ continue;
+ }
+
+ /* If the new object is a directory and the previous object does
+ * not exist assume it's also a directory and skip further checks.
+ * XXX: Ideally with more information about the installed files we
+ * could perform more clever checks. */
+ if (statr != 0 && ti->type == TAR_FILETYPE_DIR) {
+ debug(dbg_eachfile, "tarobject ... assuming shared directory");
+ continue;
+ }
+
+ ensure_package_clientdata(otherpkg);
+
+ /* Nope? Hmm, file conflict, perhaps. Check Replaces. */
+ switch (otherpkg->clientdata->replacingfilesandsaid) {
+ case 2:
+ keepexisting = true;
+ /* Fall through. */
+ case 1:
+ continue;
+ }
+
+ /* Is the package with the conflicting file in the “config files only”
+ * state? If so it must be a config file and we can silently take it
+ * over. */
+ if (otherpkg->status == PKG_STAT_CONFIGFILES)
+ continue;
+
+ /* Perhaps we're removing a conflicting package? */
+ if (otherpkg->clientdata->istobe == PKG_ISTOBE_REMOVE)
+ continue;
+
+ /* Is the file an obsolete conffile in the other package
+ * and a conffile in the new package? */
+ if ((nifd->namenode->flags & FNNF_NEW_CONFF) &&
+ !statr && S_ISREG(stab.st_mode)) {
+ for (conff = otherpkg->installed.conffiles;
+ conff;
+ conff = conff->next) {
+ if (!conff->obsolete)
+ continue;
+ if (strcmp(conff->name, nifd->namenode->name) == 0)
+ break;
+ }
+ if (conff) {
+ debug(dbg_eachfiledetail, "tarobject other's obsolete conffile");
+ /* process_archive() will have copied its hash already. */
+ continue;
+ }
+ }
+
+ if (does_replace(tc->pkg, &tc->pkg->available,
+ otherpkg, &otherpkg->installed)) {
+ printf(_("Replacing files in old package %s (%s) ...\n"),
+ pkg_name(otherpkg, pnaw_nonambig),
+ versiondescribe(&otherpkg->installed.version, vdew_nonambig));
+ otherpkg->clientdata->replacingfilesandsaid = 1;
+ } else if (does_replace(otherpkg, &otherpkg->installed,
+ tc->pkg, &tc->pkg->available)) {
+ printf(_("Replaced by files in installed package %s (%s) ...\n"),
+ pkg_name(otherpkg, pnaw_nonambig),
+ versiondescribe(&otherpkg->installed.version, vdew_nonambig));
+ otherpkg->clientdata->replacingfilesandsaid = 2;
+ nifd->namenode->flags &= ~FNNF_NEW_INARCHIVE;
+ keepexisting = true;
+ } else {
+ /* At this point we are replacing something without a Replaces. */
+ if (!statr && S_ISDIR(stab.st_mode)) {
+ forcibleerr(FORCE_OVERWRITE_DIR,
+ _("trying to overwrite directory '%.250s' "
+ "in package %.250s %.250s with nondirectory"),
+ nifd->namenode->name, pkg_name(otherpkg, pnaw_nonambig),
+ versiondescribe(&otherpkg->installed.version,
+ vdew_nonambig));
+ } else {
+ forcibleerr(FORCE_OVERWRITE,
+ _("trying to overwrite '%.250s', "
+ "which is also in package %.250s %.250s"),
+ nifd->namenode->name, pkg_name(otherpkg, pnaw_nonambig),
+ versiondescribe(&otherpkg->installed.version,
+ vdew_nonambig));
+ }
+ }
+ }
+ fsys_node_pkgs_iter_free(iter);
+ }
+
+ if (keepexisting) {
+ if (nifd->namenode->flags & FNNF_NEW_CONFF)
+ nifd->namenode->flags |= FNNF_OBS_CONFF;
+ tar_fsys_namenode_queue_pop(tc->newfiles_queue, oldnifd, nifd);
+ tarobject_skip_entry(tc, ti);
+ return 0;
+ }
+
+ if (filter_should_skip(ti)) {
+ nifd->namenode->flags &= ~FNNF_NEW_INARCHIVE;
+ nifd->namenode->flags |= FNNF_FILTERED;
+ tarobject_skip_entry(tc, ti);
+
+ return 0;
+ }
+
+ if (existingdir)
+ return 0;
+
+ /* Compute the hash of the previous object, before we might replace it
+ * with the new version on forced overwrites. */
+ if (refcounting) {
+ debug(dbg_eachfiledetail, "tarobject computing on-disk file '%s' digest, refcounting",
+ fnamevb.buf);
+ if (nifd->namenode->flags & FNNF_NEW_CONFF) {
+ md5hash_prev_conffile(tc->pkg, oldhash, fnamenewvb.buf, nifd->namenode);
+ } else if (S_ISREG(stab.st_mode)) {
+ md5hash(tc->pkg, oldhash, fnamevb.buf);
+ } else {
+ strcpy(oldhash, EMPTYHASHFLAG);
+ }
+ }
+
+ if (refcounting && !in_force(FORCE_OVERWRITE)) {
+ /* If we are not forced to overwrite the path and are refcounting,
+ * just compute the hash w/o extracting the object. */
+ tarobject_hash(tc, ti, nifd->namenode);
+ } else {
+ /* Now, at this stage we want to make sure neither of .dpkg-new and
+ * .dpkg-tmp are hanging around. */
+ path_remove_tree(fnamenewvb.buf);
+ path_remove_tree(fnametmpvb.buf);
+
+ /* Now we start to do things that we need to be able to undo
+ * if something goes wrong. Watch out for the CLEANUP comments to
+ * keep an eye on what's installed on the disk at each point. */
+ push_cleanup(cu_installnew, ~ehflag_normaltidy, 1, nifd->namenode);
+
+ /*
+ * CLEANUP: Now we either have the old file on the disk, or not, in
+ * its original filename.
+ */
+
+ /* Extract whatever it is as .dpkg-new ... */
+ tarobject_extract(tc, ti, fnamenewvb.buf, &nodestat, nifd->namenode);
+ }
+
+ /* For shared files, check now if the object matches. */
+ if (refcounting)
+ tarobject_matches(tc, fnamevb.buf, &stab, oldhash,
+ fnamenewvb.buf, ti, nifd->namenode);
+
+ /* If we didn't extract anything, there's nothing else to do. */
+ if (refcounting && !in_force(FORCE_OVERWRITE))
+ return 0;
+
+ tarobject_set_perms(ti, fnamenewvb.buf, &nodestat);
+ tarobject_set_mtime(ti, fnamenewvb.buf);
+ tarobject_set_se_context(fnamevb.buf, fnamenewvb.buf, nodestat.mode);
+
+ /*
+ * CLEANUP: Now we have extracted the new object in .dpkg-new (or,
+ * if the file already exists as a directory and we were trying to
+ * extract a directory or symlink, we returned earlier, so we don't
+ * need to worry about that here).
+ *
+ * The old file is still in the original filename,
+ */
+
+ /* First, check to see if it's a conffile. If so we don't install
+ * it now - we leave it in .dpkg-new for --configure to take care of. */
+ if (nifd->namenode->flags & FNNF_NEW_CONFF) {
+ debug(dbg_conffdetail,"tarobject conffile extracted");
+ nifd->namenode->flags |= FNNF_ELIDE_OTHER_LISTS;
+ return 0;
+ }
+
+ /* Now we move the old file out of the way, the backup file will
+ * be deleted later. */
+ if (statr) {
+ /* Don't try to back it up if it didn't exist. */
+ debug(dbg_eachfiledetail,"tarobject new - no backup");
+ } else {
+ if (ti->type == TAR_FILETYPE_DIR || S_ISDIR(stab.st_mode)) {
+ /* One of the two is a directory - can't do atomic install. */
+ debug(dbg_eachfiledetail,"tarobject directory, nonatomic");
+ nifd->namenode->flags |= FNNF_NO_ATOMIC_OVERWRITE;
+ if (rename(fnamevb.buf,fnametmpvb.buf))
+ ohshite(_("unable to move aside '%.255s' to install new version"),
+ ti->name);
+ } else if (S_ISLNK(stab.st_mode)) {
+ int rc;
+
+ /* We can't make a symlink with two hardlinks, so we'll have to
+ * copy it. (Pretend that making a copy of a symlink is the same
+ * as linking to it.) */
+ varbuf_reset(&symlinkfn);
+ varbuf_grow(&symlinkfn, stab.st_size + 1);
+ r = readlink(fnamevb.buf, symlinkfn.buf, symlinkfn.size);
+ if (r < 0)
+ ohshite(_("unable to read link '%.255s'"), ti->name);
+ else if (r > stab.st_size)
+ ohshit(_("symbolic link '%.250s' size has changed from %jd to %zd"),
+ fnamevb.buf, (intmax_t)stab.st_size, r);
+ else if (r < stab.st_size)
+ warning(_("symbolic link '%.250s' size has changed from %jd to %zd"),
+ fnamevb.buf, (intmax_t)stab.st_size, r);
+ varbuf_trunc(&symlinkfn, r);
+ varbuf_end_str(&symlinkfn);
+ if (symlink(symlinkfn.buf,fnametmpvb.buf))
+ ohshite(_("unable to make backup symlink for '%.255s'"), ti->name);
+ rc = lchown(fnametmpvb.buf, stab.st_uid, stab.st_gid);
+ if (forcible_nonroot_error(rc))
+ ohshite(_("unable to chown backup symlink for '%.255s'"), ti->name);
+ tarobject_set_se_context(fnamevb.buf, fnametmpvb.buf, stab.st_mode);
+ } else {
+ debug(dbg_eachfiledetail, "tarobject nondirectory, 'link' backup");
+ if (link(fnamevb.buf,fnametmpvb.buf))
+ ohshite(_("unable to make backup link of '%.255s' before installing new version"),
+ ti->name);
+ }
+ }
+
+ /*
+ * CLEANUP: Now the old file is in .dpkg-tmp, and the new file is still
+ * in .dpkg-new.
+ */
+
+ if (ti->type == TAR_FILETYPE_FILE || ti->type == TAR_FILETYPE_HARDLINK ||
+ ti->type == TAR_FILETYPE_SYMLINK) {
+ nifd->namenode->flags |= FNNF_DEFERRED_RENAME;
+
+ debug(dbg_eachfiledetail, "tarobject done and installation deferred");
+ } else {
+ if (rename(fnamenewvb.buf, fnamevb.buf))
+ ohshite(_("unable to install new version of '%.255s'"), ti->name);
+
+ /*
+ * CLEANUP: Now the new file is in the destination file, and the
+ * old file is in .dpkg-tmp to be cleaned up later. We now need
+ * to take a different attitude to cleanup, because we need to
+ * remove the new file.
+ */
+
+ nifd->namenode->flags |= FNNF_PLACED_ON_DISK;
+ nifd->namenode->flags |= FNNF_ELIDE_OTHER_LISTS;
+
+ debug(dbg_eachfiledetail, "tarobject done and installed");
+ }
+
+ return 0;
+}
+
+#if defined(SYNC_FILE_RANGE_WAIT_BEFORE)
+static void
+tar_writeback_barrier(struct fsys_namenode_list *files, struct pkginfo *pkg)
+{
+ struct fsys_namenode_list *cfile;
+
+ for (cfile = files; cfile; cfile = cfile->next) {
+ struct fsys_namenode *usenode;
+ int fd;
+
+ if (!(cfile->namenode->flags & FNNF_DEFERRED_FSYNC))
+ continue;
+
+ usenode = namenodetouse(cfile->namenode, pkg, &pkg->available);
+
+ setupfnamevbs(usenode->name);
+
+ fd = open(fnamenewvb.buf, O_WRONLY);
+ if (fd < 0)
+ ohshite(_("unable to open '%.255s'"), fnamenewvb.buf);
+ /* Ignore the return code as it should be considered equivalent to an
+ * asynchronous hint for the kernel, we are doing an fsync() later on
+ * anyway. */
+ sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WAIT_BEFORE);
+ if (close(fd))
+ ohshite(_("error closing/writing '%.255s'"), fnamenewvb.buf);
+ }
+}
+#else
+static void
+tar_writeback_barrier(struct fsys_namenode_list *files, struct pkginfo *pkg)
+{
+}
+#endif
+
+void
+tar_deferred_extract(struct fsys_namenode_list *files, struct pkginfo *pkg)
+{
+ struct fsys_namenode_list *cfile;
+ struct fsys_namenode *usenode;
+
+ tar_writeback_barrier(files, pkg);
+
+ for (cfile = files; cfile; cfile = cfile->next) {
+ debug(dbg_eachfile, "deferred extract of '%.255s'", cfile->namenode->name);
+
+ if (!(cfile->namenode->flags & FNNF_DEFERRED_RENAME))
+ continue;
+
+ usenode = namenodetouse(cfile->namenode, pkg, &pkg->available);
+
+ setupfnamevbs(usenode->name);
+
+ if (cfile->namenode->flags & FNNF_DEFERRED_FSYNC) {
+ int fd;
+
+ debug(dbg_eachfiledetail, "deferred extract needs fsync");
+
+ fd = open(fnamenewvb.buf, O_WRONLY);
+ if (fd < 0)
+ ohshite(_("unable to open '%.255s'"), fnamenewvb.buf);
+ if (fsync(fd))
+ ohshite(_("unable to sync file '%.255s'"), fnamenewvb.buf);
+ if (close(fd))
+ ohshite(_("error closing/writing '%.255s'"), fnamenewvb.buf);
+
+ cfile->namenode->flags &= ~FNNF_DEFERRED_FSYNC;
+ }
+
+ debug(dbg_eachfiledetail, "deferred extract needs rename");
+
+ if (rename(fnamenewvb.buf, fnamevb.buf))
+ ohshite(_("unable to install new version of '%.255s'"),
+ cfile->namenode->name);
+
+ cfile->namenode->flags &= ~FNNF_DEFERRED_RENAME;
+
+ /*
+ * CLEANUP: Now the new file is in the destination file, and the
+ * old file is in .dpkg-tmp to be cleaned up later. We now need
+ * to take a different attitude to cleanup, because we need to
+ * remove the new file.
+ */
+
+ cfile->namenode->flags |= FNNF_PLACED_ON_DISK;
+ cfile->namenode->flags |= FNNF_ELIDE_OTHER_LISTS;
+
+ debug(dbg_eachfiledetail, "deferred extract done and installed");
+ }
+}
+
+void
+enqueue_deconfigure(struct pkginfo *pkg, struct pkginfo *pkg_removal,
+ enum pkgwant reason)
+{
+ struct pkg_deconf_list *newdeconf;
+
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->istobe = PKG_ISTOBE_DECONFIGURE;
+ newdeconf = m_malloc(sizeof(*newdeconf));
+ newdeconf->next = deconfigure;
+ newdeconf->pkg = pkg;
+ newdeconf->pkg_removal = pkg_removal;
+ newdeconf->reason = reason;
+ deconfigure = newdeconf;
+}
+
+void
+clear_deconfigure_queue(void)
+{
+ struct pkg_deconf_list *deconf, *deconf_next;
+
+ for (deconf = deconfigure; deconf; deconf = deconf_next) {
+ deconf_next = deconf->next;
+ free(deconf);
+ }
+ deconfigure = NULL;
+}
+
+/**
+ * Try if we can deconfigure the package for installation and queue it if so.
+ *
+ * This function gets called in the Breaks context, when trying to install
+ * a package that might require another to be deconfigured to be able to
+ * proceed.
+ *
+ * First checks whether the pdep is forced.
+ *
+ * @retval 0 Not possible (why is printed).
+ * @retval 1 Deconfiguration queued ok (no message printed).
+ * @retval 2 Forced (no deconfiguration needed, why is printed).
+ */
+static int
+try_deconfigure_can(struct pkginfo *pkg, struct deppossi *pdep,
+ struct pkginfo *pkg_install, const char *why)
+{
+ if (force_breaks(pdep)) {
+ warning(_("ignoring dependency problem with installation of %s:\n%s"),
+ pkgbin_name(pkg_install, &pkg->available, pnaw_nonambig), why);
+ return 2;
+ } else if (f_autodeconf) {
+ enqueue_deconfigure(pkg, NULL, PKG_WANT_INSTALL);
+ return 1;
+ } else {
+ notice(_("no, cannot proceed with installation of %s (--auto-deconfigure will help):\n%s"),
+ pkgbin_name(pkg_install, &pkg->available, pnaw_nonambig), why);
+ return 0;
+ }
+}
+
+/**
+ * Try if we can deconfigure the package for removal and queue it if so.
+ *
+ * This function gets called in the Conflicts+Depends context, when trying
+ * to install a package that might require another to be fully removed to
+ * be able to proceed.
+ *
+ * First checks whether the pdep is forced, then if auto-configure is enabled
+ * we make sure Essential and Protected are not allowed to be removed unless
+ * forced.
+ *
+ * @retval 0 Not possible (why is printed).
+ * @retval 1 Deconfiguration queued ok (no message printed).
+ * @retval 2 Forced (no deconfiguration needed, why is printed).
+ */
+static int
+try_remove_can(struct deppossi *pdep,
+ struct pkginfo *pkg_removal, const char *why)
+{
+ struct pkginfo *pkg = pdep->up->up;
+
+ if (force_depends(pdep)) {
+ warning(_("ignoring dependency problem with removal of %s:\n%s"),
+ pkg_name(pkg_removal, pnaw_nonambig), why);
+ return 2;
+ } else if (f_autodeconf) {
+ if (pkg->installed.essential) {
+ if (in_force(FORCE_REMOVE_ESSENTIAL)) {
+ warning(_("considering deconfiguration of essential\n"
+ " package %s, to enable removal of %s"),
+ pkg_name(pkg, pnaw_nonambig), pkg_name(pkg_removal, pnaw_nonambig));
+ } else {
+ notice(_("no, %s is essential, will not deconfigure\n"
+ " it in order to enable removal of %s"),
+ pkg_name(pkg, pnaw_nonambig), pkg_name(pkg_removal, pnaw_nonambig));
+ return 0;
+ }
+ }
+ if (pkg->installed.is_protected) {
+ if (in_force(FORCE_REMOVE_PROTECTED)) {
+ warning(_("considering deconfiguration of protected\n"
+ " package %s, to enable removal of %s"),
+ pkg_name(pkg, pnaw_nonambig), pkg_name(pkg_removal, pnaw_nonambig));
+ } else {
+ notice(_("no, %s is protected, will not deconfigure\n"
+ " it in order to enable removal of %s"),
+ pkg_name(pkg, pnaw_nonambig), pkg_name(pkg_removal, pnaw_nonambig));
+ return 0;
+ }
+ }
+
+ enqueue_deconfigure(pkg, pkg_removal, PKG_WANT_DEINSTALL);
+ return 1;
+ } else {
+ notice(_("no, cannot proceed with removal of %s (--auto-deconfigure will help):\n%s"),
+ pkg_name(pkg_removal, pnaw_nonambig), why);
+ return 0;
+ }
+}
+
+void check_breaks(struct dependency *dep, struct pkginfo *pkg,
+ const char *pfilename) {
+ struct pkginfo *fixbydeconf;
+ struct varbuf why = VARBUF_INIT;
+ int ok;
+
+ fixbydeconf = NULL;
+ if (depisok(dep, &why, &fixbydeconf, NULL, false)) {
+ varbuf_destroy(&why);
+ return;
+ }
+
+ varbuf_end_str(&why);
+
+ if (fixbydeconf && f_autodeconf) {
+ ensure_package_clientdata(fixbydeconf);
+
+ if (fixbydeconf->clientdata->istobe != PKG_ISTOBE_NORMAL)
+ internerr("package %s being fixed by deconf is not to be normal, "
+ "is to be %d",
+ pkg_name(pkg, pnaw_always), fixbydeconf->clientdata->istobe);
+
+ notice(_("considering deconfiguration of %s, which would be broken by installation of %s ..."),
+ pkg_name(fixbydeconf, pnaw_nonambig),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+
+ ok = try_deconfigure_can(fixbydeconf, dep->list, pkg, why.buf);
+ if (ok == 1) {
+ notice(_("yes, will deconfigure %s (broken by %s)"),
+ pkg_name(fixbydeconf, pnaw_nonambig),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ }
+ } else {
+ notice(_("regarding %s containing %s:\n%s"), pfilename,
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig), why.buf);
+ ok= 0;
+ }
+ varbuf_destroy(&why);
+ if (ok > 0) return;
+
+ if (force_breaks(dep->list)) {
+ warning(_("ignoring breakage, may proceed anyway!"));
+ return;
+ }
+
+ if (fixbydeconf && !f_autodeconf) {
+ ohshit(_("installing %.250s would break %.250s, and\n"
+ " deconfiguration is not permitted (--auto-deconfigure might help)"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ pkg_name(fixbydeconf, pnaw_nonambig));
+ } else {
+ ohshit(_("installing %.250s would break existing software"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ }
+}
+
+void check_conflict(struct dependency *dep, struct pkginfo *pkg,
+ const char *pfilename) {
+ struct pkginfo *fixbyrm;
+ struct deppossi *pdep, flagdeppossi = { 0 };
+ struct varbuf conflictwhy = VARBUF_INIT, removalwhy = VARBUF_INIT;
+ struct dependency *providecheck;
+
+ fixbyrm = NULL;
+ if (depisok(dep, &conflictwhy, &fixbyrm, NULL, false)) {
+ varbuf_destroy(&conflictwhy);
+ varbuf_destroy(&removalwhy);
+ return;
+ }
+ if (fixbyrm) {
+ ensure_package_clientdata(fixbyrm);
+ if (fixbyrm->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) {
+ fixbyrm= dep->up;
+ ensure_package_clientdata(fixbyrm);
+ }
+ if (((pkg->available.essential || pkg->available.is_protected) &&
+ (fixbyrm->installed.essential || fixbyrm->installed.is_protected)) ||
+ (((fixbyrm->want != PKG_WANT_INSTALL &&
+ fixbyrm->want != PKG_WANT_HOLD) ||
+ does_replace(pkg, &pkg->available, fixbyrm, &fixbyrm->installed)) &&
+ ((!fixbyrm->installed.essential || in_force(FORCE_REMOVE_ESSENTIAL)) ||
+ (!fixbyrm->installed.is_protected || in_force(FORCE_REMOVE_PROTECTED))))) {
+ if (fixbyrm->clientdata->istobe != PKG_ISTOBE_NORMAL &&
+ fixbyrm->clientdata->istobe != PKG_ISTOBE_DECONFIGURE)
+ internerr("package %s to be fixed by removal is not to be normal "
+ "nor deconfigure, is to be %d",
+ pkg_name(pkg, pnaw_always), fixbyrm->clientdata->istobe);
+ fixbyrm->clientdata->istobe = PKG_ISTOBE_REMOVE;
+ notice(_("considering removing %s in favour of %s ..."),
+ pkg_name(fixbyrm, pnaw_nonambig),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ if (!(fixbyrm->status == PKG_STAT_INSTALLED ||
+ fixbyrm->status == PKG_STAT_TRIGGERSPENDING ||
+ fixbyrm->status == PKG_STAT_TRIGGERSAWAITED)) {
+ notice(_("%s is not properly installed; ignoring any dependencies on it"),
+ pkg_name(fixbyrm, pnaw_nonambig));
+ pdep = NULL;
+ } else {
+ for (pdep = fixbyrm->set->depended.installed;
+ pdep;
+ pdep = pdep->rev_next) {
+ if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends)
+ continue;
+ if (depisok(pdep->up, &removalwhy, NULL, NULL, false))
+ continue;
+ varbuf_end_str(&removalwhy);
+ if (!try_remove_can(pdep,fixbyrm,removalwhy.buf))
+ break;
+ }
+ if (!pdep) {
+ /* If we haven't found a reason not to yet, let's look some more. */
+ for (providecheck= fixbyrm->installed.depends;
+ providecheck;
+ providecheck= providecheck->next) {
+ if (providecheck->type != dep_provides) continue;
+ for (pdep = providecheck->list->ed->depended.installed;
+ pdep;
+ pdep = pdep->rev_next) {
+ if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends)
+ continue;
+ if (depisok(pdep->up, &removalwhy, NULL, NULL, false))
+ continue;
+ varbuf_end_str(&removalwhy);
+ notice(_("may have trouble removing %s, as it provides %s ..."),
+ pkg_name(fixbyrm, pnaw_nonambig),
+ providecheck->list->ed->name);
+ if (!try_remove_can(pdep,fixbyrm,removalwhy.buf))
+ goto break_from_both_loops_at_once;
+ }
+ }
+ break_from_both_loops_at_once:;
+ }
+ }
+ if (!pdep && skip_due_to_hold(fixbyrm)) {
+ pdep= &flagdeppossi;
+ }
+ if (!pdep && (fixbyrm->eflag & PKG_EFLAG_REINSTREQ)) {
+ if (in_force(FORCE_REMOVE_REINSTREQ)) {
+ notice(_("package %s requires reinstallation, but will "
+ "remove anyway as you requested"),
+ pkg_name(fixbyrm, pnaw_nonambig));
+ } else {
+ notice(_("package %s requires reinstallation, will not remove"),
+ pkg_name(fixbyrm, pnaw_nonambig));
+ pdep= &flagdeppossi;
+ }
+ }
+ if (!pdep) {
+ /* This conflict is OK - we'll remove the conflictor. */
+ enqueue_conflictor(fixbyrm);
+ varbuf_destroy(&conflictwhy); varbuf_destroy(&removalwhy);
+ notice(_("yes, will remove %s in favour of %s"),
+ pkg_name(fixbyrm, pnaw_nonambig),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ return;
+ }
+ /* Put it back. */
+ fixbyrm->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ }
+ }
+ varbuf_end_str(&conflictwhy);
+ notice(_("regarding %s containing %s:\n%s"), pfilename,
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig), conflictwhy.buf);
+ if (!force_conflicts(dep->list))
+ ohshit(_("conflicting packages - not installing %.250s"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ warning(_("ignoring conflict, may proceed anyway!"));
+ varbuf_destroy(&conflictwhy);
+
+ return;
+}
+
+void cu_cidir(int argc, void **argv) {
+ char *cidir= (char*)argv[0];
+ char *cidirrest= (char*)argv[1];
+ cidirrest[-1] = '\0';
+ path_remove_tree(cidir);
+ free(cidir);
+}
+
+void cu_fileslist(int argc, void **argv) {
+ tar_pool_release();
+}
+
+int
+archivefiles(const char *const *argv)
+{
+ const char *const *volatile argp;
+ char **volatile arglist = NULL;
+ int i;
+ jmp_buf ejbuf;
+ enum modstatdb_rw msdbflags;
+
+ trigproc_install_hooks();
+
+ if (f_noact)
+ msdbflags = msdbrw_readonly;
+ else if (cipaction->arg_int == act_avail)
+ msdbflags = msdbrw_readonly | msdbrw_available_write;
+ else if (in_force(FORCE_NON_ROOT))
+ msdbflags = msdbrw_write;
+ else
+ msdbflags = msdbrw_needsuperuser;
+
+ modstatdb_open(msdbflags);
+
+ checkpath();
+ pkg_infodb_upgrade();
+
+ log_message("startup archives %s", cipaction->olong);
+
+ if (f_recursive) {
+ const char *const *ap;
+ int nfiles = 0;
+
+ if (!*argv)
+ badusage(_("--%s --recursive needs at least one path argument"),cipaction->olong);
+
+ for (ap = argv; *ap; ap++) {
+ struct treeroot *tree;
+ struct treenode *node;
+
+ tree = treewalk_open((const char *)*ap, TREEWALK_FOLLOW_LINKS, NULL);
+
+ while ((node = treewalk_next(tree))) {
+ const char *nodename;
+
+ if (!S_ISREG(treenode_get_mode(node)))
+ continue;
+
+ /* Check if it looks like a .deb file. */
+ nodename = treenode_get_pathname(node);
+ if (strcmp(nodename + strlen(nodename) - 4, ".deb") != 0)
+ continue;
+
+ arglist = m_realloc(arglist, sizeof(char *) * (nfiles + 2));
+ arglist[nfiles++] = m_strdup(nodename);
+ }
+
+ treewalk_close(tree);
+ }
+
+ if (!nfiles)
+ ohshit(_("searched, but found no packages (files matching *.deb)"));
+
+ arglist[nfiles] = NULL;
+ argp = (const char **volatile)arglist;
+ } else {
+ if (!*argv) badusage(_("--%s needs at least one package archive file argument"),
+ cipaction->olong);
+ argp= argv;
+ }
+
+ /* Perform some sanity checks on the passed archives. */
+ for (i = 0; argp[i]; i++) {
+ struct stat st;
+
+ /* We need the filename to exist. */
+ if (stat(argp[i], &st) < 0)
+ ohshite(_("cannot access archive '%s'"), argp[i]);
+
+ /* We cannot work with anything that is not a regular file. */
+ if (!S_ISREG(st.st_mode))
+ ohshit(_("archive '%s' is not a regular file"), argp[i]);
+ }
+
+ currenttime = time(NULL);
+
+ /* Initialize fname variables contents. */
+
+ varbuf_reset(&fnamevb);
+ varbuf_reset(&fnametmpvb);
+ varbuf_reset(&fnamenewvb);
+
+ varbuf_add_str(&fnamevb, dpkg_fsys_get_dir());
+ varbuf_add_str(&fnametmpvb, dpkg_fsys_get_dir());
+ varbuf_add_str(&fnamenewvb, dpkg_fsys_get_dir());
+
+ varbuf_snapshot(&fnamevb, &fname_state);
+ varbuf_snapshot(&fnametmpvb, &fnametmp_state);
+ varbuf_snapshot(&fnamenewvb, &fnamenew_state);
+
+ ensure_diversions();
+ ensure_statoverrides(STATDB_PARSE_NORMAL);
+
+ for (i = 0; argp[i]; i++) {
+ if (setjmp(ejbuf)) {
+ pop_error_context(ehflag_bombout);
+ if (abort_processing)
+ break;
+ continue;
+ }
+ push_error_context_jump(&ejbuf, print_error_perarchive, argp[i]);
+
+ dpkg_selabel_load();
+
+ process_archive(argp[i]);
+ onerr_abort++;
+ m_output(stdout, _("<standard output>"));
+ m_output(stderr, _("<standard error>"));
+ onerr_abort--;
+
+ pop_error_context(ehflag_normaltidy);
+ }
+
+ dpkg_selabel_close();
+
+ if (arglist) {
+ for (i = 0; arglist[i]; i++)
+ free(arglist[i]);
+ free(arglist);
+ }
+
+ switch (cipaction->arg_int) {
+ case act_install:
+ case act_configure:
+ case act_triggers:
+ case act_remove:
+ case act_purge:
+ process_queue();
+ case act_unpack:
+ case act_avail:
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+
+ trigproc_run_deferred();
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+/**
+ * Decide whether we want to install a new version of the package.
+ *
+ * @param pkg The package with the version we might want to install
+ *
+ * @retval true If the package should be skipped.
+ * @retval false If the package should be installed.
+ */
+bool
+wanttoinstall(struct pkginfo *pkg)
+{
+ int rc;
+
+ if (pkg->want != PKG_WANT_INSTALL && pkg->want != PKG_WANT_HOLD) {
+ if (f_alsoselect) {
+ printf(_("Selecting previously unselected package %s.\n"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ return true;
+ } else {
+ printf(_("Skipping unselected package %s.\n"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ return false;
+ }
+ }
+
+ if (pkg->eflag & PKG_EFLAG_REINSTREQ)
+ return true;
+ if (pkg->status < PKG_STAT_UNPACKED)
+ return true;
+
+ rc = dpkg_version_compare(&pkg->available.version, &pkg->installed.version);
+ if (rc > 0) {
+ return true;
+ } else if (rc == 0) {
+ /* Same version fully installed. */
+ if (f_skipsame && pkg->available.arch == pkg->installed.arch) {
+ notice(_("version %.250s of %.250s already installed, skipping"),
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ pkg_name(pkg, pnaw_nonambig));
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ if (in_force(FORCE_DOWNGRADE)) {
+ warning(_("downgrading %.250s from %.250s to %.250s"),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig));
+ return true;
+ } else {
+ notice(_("will not downgrade %.250s from %.250s to %.250s, skipping"),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig));
+ return false;
+ }
+ }
+}
diff --git a/src/main/archives.h b/src/main/archives.h
new file mode 100644
index 0000000..3d97446
--- /dev/null
+++ b/src/main/archives.h
@@ -0,0 +1,99 @@
+/*
+ * dpkg - main program for package management
+ * archives.h - functions common to archives.c and unpack.c
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2008-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/>.
+ */
+
+#ifndef ARCHIVES_H
+#define ARCHIVES_H
+
+#include <stdbool.h>
+
+#include <dpkg/tarfn.h>
+
+struct tarcontext {
+ int backendpipe;
+ struct pkginfo *pkg;
+ /** A queue of fsys_namenode that have been extracted anew. */
+ struct fsys_namenode_queue *newfiles_queue;
+ /** Are all “Multi-arch: same” instances about to be in sync? */
+ bool pkgset_getting_in_sync;
+};
+
+struct pkg_deconf_list {
+ struct pkg_deconf_list *next;
+ struct pkginfo *pkg;
+ struct pkginfo *pkg_removal;
+ enum pkgwant reason;
+};
+
+extern struct varbuf_state fname_state;
+extern struct varbuf_state fnametmp_state;
+extern struct varbuf_state fnamenew_state;
+extern struct varbuf fnamevb;
+extern struct varbuf fnametmpvb;
+extern struct varbuf fnamenewvb;
+extern struct pkg_deconf_list *deconfigure;
+
+void clear_deconfigure_queue(void);
+void enqueue_deconfigure(struct pkginfo *pkg, struct pkginfo *pkg_removal,
+ enum pkgwant reason);
+void enqueue_conflictor(struct pkginfo *pkg);
+
+void cu_pathname(int argc, void **argv);
+void cu_cidir(int argc, void **argv);
+void cu_fileslist(int argc, void **argv);
+void cu_backendpipe(int argc, void **argv);
+
+void cu_installnew(int argc, void **argv);
+
+void cu_prermupgrade(int argc, void **argv);
+void cu_prerminfavour(int argc, void **argv);
+void cu_preinstverynew(int argc, void **argv);
+void cu_preinstnew(int argc, void **argv);
+void cu_preinstupgrade(int argc, void **argv);
+void cu_postrmupgrade(int argc, void **argv);
+
+void cu_prermdeconfigure(int argc, void **argv);
+void ok_prermdeconfigure(int argc, void **argv);
+
+void setupfnamevbs(const char *filename);
+
+int
+tarobject(struct tar_archive *tar, struct tar_entry *ti);
+int
+tarfileread(struct tar_archive *tar, char *buf, int len);
+void
+tar_deferred_extract(struct fsys_namenode_list *files, struct pkginfo *pkg);
+
+struct fsys_namenode_list *
+tar_fsys_namenode_queue_push(struct fsys_namenode_queue *queue,
+ struct fsys_namenode *namenode);
+
+bool
+filesavespackage(struct fsys_namenode_list *, struct pkginfo *,
+ struct pkginfo *pkgbeinginstalled);
+
+void check_conflict(struct dependency *dep, struct pkginfo *pkg,
+ const char *pfilename);
+void check_breaks(struct dependency *dep, struct pkginfo *pkg,
+ const char *pfilename);
+
+extern int cleanup_pkg_failed, cleanup_conflictor_failed;
+
+#endif /* ARCHIVES_H */
diff --git a/src/main/cleanup.c b/src/main/cleanup.c
new file mode 100644
index 0000000..d33e5cb
--- /dev/null
+++ b/src/main/cleanup.c
@@ -0,0 +1,260 @@
+/*
+ * dpkg - main program for package management
+ * cleanup.c - cleanup functions, used when we need to unwind
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-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 <errno.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.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/pkg.h>
+#include <dpkg/path.h>
+#include <dpkg/options.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+#include "archives.h"
+
+int cleanup_pkg_failed=0, cleanup_conflictor_failed=0;
+
+/**
+ * Something went wrong and we're undoing.
+ *
+ * We have the following possible situations for non-conffiles:
+ * «pathname».dpkg-tmp exists - in this case we want to remove
+ * «pathname» if it exists and replace it with «pathname».dpkg-tmp.
+ * This undoes the backup operation.
+ * «pathname».dpkg-tmp does not exist - «pathname» may be on the disk,
+ * as a new file which didn't fail, remove it if it is.
+ *
+ * In both cases, we also make sure we delete «pathname».dpkg-new in
+ * case that's still hanging around.
+ *
+ * For conffiles, we simply delete «pathname».dpkg-new. For these,
+ * «pathname».dpkg-tmp shouldn't exist, as we don't make a backup
+ * at this stage. Just to be on the safe side, though, we don't
+ * look for it.
+ */
+void cu_installnew(int argc, void **argv) {
+ struct fsys_namenode *namenode = argv[0];
+ struct stat stab;
+
+ cleanup_pkg_failed++; cleanup_conflictor_failed++;
+
+ debug(dbg_eachfile, "cu_installnew '%s' flags=%o",
+ namenode->name, namenode->flags);
+
+ setupfnamevbs(namenode->name);
+
+ if (!(namenode->flags & FNNF_NEW_CONFF) && !lstat(fnametmpvb.buf,&stab)) {
+ /* OK, «pathname».dpkg-tmp exists. Remove «pathname» and
+ * restore «pathname».dpkg-tmp ... */
+ if (namenode->flags & FNNF_NO_ATOMIC_OVERWRITE) {
+ /* If we can't do an atomic overwrite we have to delete first any
+ * link to the new version we may have created. */
+ debug(dbg_eachfiledetail,"cu_installnew restoring nonatomic");
+ if (secure_remove(fnamevb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-installed version of '%.250s' to allow"
+ " reinstallation of backup copy"),namenode->name);
+ } else {
+ debug(dbg_eachfiledetail,"cu_installnew restoring atomic");
+ }
+ /* Either we can do an atomic restore, or we've made room: */
+ if (rename(fnametmpvb.buf,fnamevb.buf))
+ ohshite(_("unable to restore backup version of '%.250s'"), namenode->name);
+ /* If «pathname».dpkg-tmp was still a hard link to «pathname», then the
+ * atomic rename did nothing, so we make sure to remove the backup. */
+ else if (unlink(fnametmpvb.buf) && errno != ENOENT)
+ ohshite(_("unable to remove backup copy of '%.250s'"), namenode->name);
+ } else if (namenode->flags & FNNF_PLACED_ON_DISK) {
+ debug(dbg_eachfiledetail,"cu_installnew removing new file");
+ if (secure_remove(fnamevb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-installed version of '%.250s'"),
+ namenode->name);
+ } else {
+ debug(dbg_eachfiledetail,"cu_installnew not restoring");
+ }
+ /* Whatever, we delete «pathname».dpkg-new now, if it still exists. */
+ if (secure_remove(fnamenewvb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-extracted version of '%.250s'"),
+ namenode->name);
+
+ cleanup_pkg_failed--; cleanup_conflictor_failed--;
+}
+
+void cu_prermupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_postinst(pkg, "abort-upgrade",
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(pkg, PKG_STAT_INSTALLED);
+ cleanup_pkg_failed--;
+}
+
+/*
+ * Also has conflictor in argv[1] and infavour in argv[2].
+ * conflictor may be NULL if deconfigure was due to Breaks or multi-arch
+ * instance sync.
+ */
+void ok_prermdeconfigure(int argc, void **argv) {
+ struct pkginfo *deconf= (struct pkginfo*)argv[0];
+
+ if (cipaction->arg_int == act_install)
+ enqueue_package(deconf);
+}
+
+/*
+ * conflictor may be NULL if deconfigure was due to Breaks or multi-arch
+ * instance sync.
+ */
+void cu_prermdeconfigure(int argc, void **argv) {
+ struct pkginfo *deconf= (struct pkginfo*)argv[0];
+ struct pkginfo *conflictor = (struct pkginfo *)argv[1];
+ struct pkginfo *infavour= (struct pkginfo*)argv[2];
+
+ if (conflictor) {
+ maintscript_postinst(deconf, "abort-deconfigure",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ "removing",
+ pkg_name(conflictor, pnaw_nonambig),
+ versiondescribe(&conflictor->installed.version,
+ vdew_nonambig),
+ NULL);
+ } else {
+ maintscript_postinst(deconf, "abort-deconfigure",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ NULL);
+ }
+
+ post_postinst_tasks(deconf, PKG_STAT_INSTALLED);
+}
+
+void cu_prerminfavour(int argc, void **argv) {
+ struct pkginfo *conflictor= (struct pkginfo*)argv[0];
+ struct pkginfo *infavour= (struct pkginfo*)argv[1];
+
+ if (cleanup_conflictor_failed++) return;
+ maintscript_postinst(conflictor, "abort-remove",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ NULL);
+ pkg_clear_eflags(conflictor, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(conflictor, PKG_STAT_INSTALLED);
+ cleanup_conflictor_failed--;
+}
+
+void cu_preinstverynew(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-install", NULL);
+ pkg_set_status(pkg, PKG_STAT_NOTINSTALLED);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ pkgbin_blank(&pkg->installed);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_preinstnew(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-install",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_set_status(pkg, PKG_STAT_CONFIGFILES);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_preinstupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+ enum pkgstatus *oldstatusp= (enum pkgstatus*)argv[3];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-upgrade",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_set_status(pkg, *oldstatusp);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_postrmupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_installed(pkg, PREINSTFILE, "pre-installation",
+ "abort-upgrade",
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ cleanup_pkg_failed--;
+}
+
+void cu_prermremove(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ enum pkgstatus *oldpkgstatus= (enum pkgstatus*)argv[1];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_postinst(pkg, "abort-remove", NULL);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(pkg, *oldpkgstatus);
+ cleanup_pkg_failed--;
+}
diff --git a/src/main/configure.c b/src/main/configure.c
new file mode 100644
index 0000000..14f300b
--- /dev/null
+++ b/src/main/configure.c
@@ -0,0 +1,829 @@
+/*
+ * dpkg - main program for package management
+ * configure.c - configure packages
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 1999, 2002 Wichert Akkerman <wichert@deephackmode.org>
+ * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/pkg.h>
+#include <dpkg/string.h>
+#include <dpkg/buffer.h>
+#include <dpkg/file.h>
+#include <dpkg/path.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/pager.h>
+#include <dpkg/triglib.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+enum conffopt {
+ CFOF_PROMPT = DPKG_BIT(0),
+ CFOF_KEEP = DPKG_BIT(1),
+ CFOF_INSTALL = DPKG_BIT(2),
+ CFOF_BACKUP = DPKG_BIT(3),
+ CFOF_NEW_CONFF = DPKG_BIT(4),
+ CFOF_IS_NEW = DPKG_BIT(5),
+ CFOF_IS_OLD = DPKG_BIT(6),
+ CFOF_USER_DEL = DPKG_BIT(7),
+
+ CFO_KEEP = CFOF_KEEP,
+ CFO_IDENTICAL = CFOF_KEEP,
+ CFO_INSTALL = CFOF_INSTALL,
+ CFO_NEW_CONFF = CFOF_NEW_CONFF | CFOF_INSTALL,
+ CFO_PROMPT = CFOF_PROMPT,
+ CFO_PROMPT_KEEP = CFOF_PROMPT | CFOF_KEEP,
+ CFO_PROMPT_INSTALL = CFOF_PROMPT | CFOF_INSTALL,
+};
+
+static int conffoptcells[2][2] = {
+ /* Distro !edited. */ /* Distro edited. */
+ { CFO_KEEP, CFO_INSTALL }, /* User !edited. */
+ { CFO_KEEP, CFO_PROMPT_KEEP }, /* User edited. */
+};
+
+static int
+show_prompt(const char *cfgfile, const char *realold, const char *realnew,
+ int useredited, int distedited, enum conffopt what)
+{
+ const char *s;
+ int c, cc;
+
+ /* Flush the terminal's input in case the user involuntarily
+ * typed some characters. */
+ tcflush(STDIN_FILENO, TCIFLUSH);
+
+ fputs("\n", stderr);
+ if (strcmp(cfgfile, realold) == 0)
+ fprintf(stderr, _("Configuration file '%s'\n"), cfgfile);
+ else
+ fprintf(stderr, _("Configuration file '%s' (actually '%s')\n"),
+ cfgfile, realold);
+
+ if (what & CFOF_IS_NEW) {
+ fprintf(stderr,
+ _(" ==> File on system created by you or by a script.\n"
+ " ==> File also in package provided by package maintainer.\n"));
+ } else {
+ fprintf(stderr, !useredited ?
+ _(" Not modified since installation.\n") :
+ !(what & CFOF_USER_DEL) ?
+ _(" ==> Modified (by you or by a script) since installation.\n") :
+ _(" ==> Deleted (by you or by a script) since installation.\n"));
+
+ fprintf(stderr, distedited ?
+ _(" ==> Package distributor has shipped an updated version.\n") :
+ _(" Version in package is the same as at last installation.\n"));
+ }
+
+ /* No --force-confdef but a forcible situation. */
+ /* TODO: check if this condition can not be simplified to
+ * just !in_force(FORCE_CONFF_DEF) */
+ if (!(in_force(FORCE_CONFF_DEF) && (what & (CFOF_INSTALL | CFOF_KEEP)))) {
+ if (in_force(FORCE_CONFF_NEW)) {
+ fprintf(stderr,
+ _(" ==> Using new file as you requested.\n"));
+ return 'y';
+ } else if (in_force(FORCE_CONFF_OLD)) {
+ fprintf(stderr,
+ _(" ==> Using current old file as you requested.\n"));
+ return 'n';
+ }
+ }
+
+ /* Force the default action (if there is one. */
+ if (in_force(FORCE_CONFF_DEF)) {
+ if (what & CFOF_KEEP) {
+ fprintf(stderr,
+ _(" ==> Keeping old config file as default.\n"));
+ return 'n';
+ } else if (what & CFOF_INSTALL) {
+ fprintf(stderr,
+ _(" ==> Using new config file as default.\n"));
+ return 'y';
+ }
+ }
+
+ fprintf(stderr,
+ _(" What would you like to do about it ? Your options are:\n"
+ " Y or I : install the package maintainer's version\n"
+ " N or O : keep your currently-installed version\n"
+ " D : show the differences between the versions\n"
+ " Z : start a shell to examine the situation\n"));
+
+ if (what & CFOF_KEEP)
+ fprintf(stderr,
+ _(" The default action is to keep your current version.\n"));
+ else if (what & CFOF_INSTALL)
+ fprintf(stderr,
+ _(" The default action is to install the new version.\n"));
+
+ s = path_basename(cfgfile);
+ fprintf(stderr, "*** %s (Y/I/N/O/D/Z) %s ? ", s,
+ (what & CFOF_KEEP) ? _("[default=N]") :
+ (what & CFOF_INSTALL) ? _("[default=Y]") :
+ _("[no default]"));
+
+ if (ferror(stderr))
+ ohshite(_("error writing to stderr, discovered before conffile prompt"));
+
+ cc = 0;
+ while ((c = getchar()) != EOF && c != '\n')
+ if (!isspace(c) && !cc)
+ cc = tolower(c);
+
+ if (c == EOF) {
+ if (ferror(stdin))
+ ohshite(_("read error on stdin at conffile prompt"));
+ ohshit(_("end of file on stdin at conffile prompt"));
+ }
+
+ if (!cc) {
+ if (what & CFOF_KEEP)
+ return 'n';
+ else if (what & CFOF_INSTALL)
+ return 'y';
+ }
+
+ return cc;
+}
+
+/**
+ * Show a diff between two files.
+ *
+ * @param old The path to the old file.
+ * @param new The path to the new file.
+ */
+static void
+show_diff(const char *old, const char *new)
+{
+ struct pager *pager;
+ pid_t pid;
+
+ pager = pager_spawn(_("conffile difference visualizer"));
+
+ pid = subproc_fork();
+ if (!pid) {
+ /* Child process. */
+ struct command cmd;
+
+ command_init(&cmd, DIFF, _("conffile difference visualizer"));
+ command_add_arg(&cmd, DIFF);
+ command_add_arg(&cmd, "-Nu");
+ command_add_arg(&cmd, old);
+ command_add_arg(&cmd, new);
+ command_exec(&cmd);
+ }
+
+ /* Parent process. */
+ subproc_reap(pid, _("conffile difference visualizer"), SUBPROC_NOCHECK);
+ pager_reap(pager);
+}
+
+/**
+ * Spawn a new shell.
+ *
+ * Create a subprocess and execute a shell to allow the user to manually
+ * solve the conffile conflict.
+ *
+ * @param confold The path to the old conffile.
+ * @param confnew The path to the new conffile.
+ */
+static void
+spawn_shell(const char *confold, const char *confnew)
+{
+ pid_t pid;
+
+ fputs(_("Useful environment variables:\n"), stderr);
+ fputs(" - DPKG_SHELL_REASON\n", stderr);
+ fputs(" - DPKG_CONFFILE_OLD\n", stderr);
+ fputs(" - DPKG_CONFFILE_NEW\n", stderr);
+ fputs(_("Type 'exit' when you're done.\n"), stderr);
+
+ pid = subproc_fork();
+ if (!pid) {
+ /* Set useful variables for the user. */
+ setenv("DPKG_SHELL_REASON", "conffile-prompt", 1);
+ setenv("DPKG_CONFFILE_OLD", confold, 1);
+ setenv("DPKG_CONFFILE_NEW", confnew, 1);
+
+ command_shell(NULL, _("conffile shell"));
+ }
+
+ /* Parent process. */
+ subproc_reap(pid, _("conffile shell"), SUBPROC_NOCHECK);
+}
+
+/**
+ * Prompt the user for how to resolve a conffile conflict.
+ *
+ * When encountering a conffile conflict during configuration, the user will
+ * normally be presented with a textual menu of possible actions. This
+ * behavior is modified via various --force flags and perhaps on whether
+ * or not a terminal is available to do the prompting.
+ *
+ * @param pkg The package owning the conffile.
+ * @param cfgfile The path to the old conffile.
+ * @param realold The path to the old conffile, dereferenced in case of a
+ * symlink, otherwise equal to cfgfile.
+ * @param realnew The path to the new conffile, dereferenced in case of a
+ * symlink).
+ * @param useredited A flag to indicate whether the file has been edited
+ * locally. Set to nonzero to indicate that the file has been modified.
+ * @param distedited A flag to indicate whether the file has been updated
+ * between package versions. Set to nonzero to indicate that the file
+ * has been updated.
+ * @param what Hints on what action should be taken by default.
+ *
+ * @return The action which should be taken based on user input and/or the
+ * default actions as configured by cmdline/configuration options.
+ */
+static enum conffopt
+promptconfaction(struct pkginfo *pkg, const char *cfgfile,
+ const char *realold, const char *realnew,
+ int useredited, int distedited, enum conffopt what)
+{
+ int cc;
+
+ if (!(what & CFOF_PROMPT))
+ return what;
+
+ statusfd_send("status: %s : %s : '%s' '%s' %i %i ",
+ cfgfile, "conffile-prompt",
+ realold, realnew, useredited, distedited);
+
+ do {
+ cc = show_prompt(cfgfile, realold, realnew,
+ useredited, distedited, what);
+
+ /* FIXME: Say something if silently not install. */
+ if (cc == 'd')
+ show_diff(realold, realnew);
+
+ if (cc == 'z')
+ spawn_shell(realold, realnew);
+ } while (!strchr("yino", cc));
+
+ log_message("conffile %s %s", cfgfile,
+ (cc == 'i' || cc == 'y') ? "install" : "keep");
+
+ what &= CFOF_USER_DEL;
+
+ switch (cc) {
+ case 'i':
+ case 'y':
+ what |= CFOF_INSTALL | CFOF_BACKUP;
+ break;
+
+ case 'n':
+ case 'o':
+ what |= CFOF_KEEP | CFOF_BACKUP;
+ break;
+
+ default:
+ internerr("unknown response '%d'", cc);
+ }
+
+ return what;
+}
+
+/**
+ * Configure the ghost conffile instance.
+ *
+ * When the first instance of a package set is configured, the *.dpkg-new
+ * files gets installed into their destination, which makes configuration of
+ * conffiles from subsequent package instances be skipped along with updates
+ * to the Conffiles field hash.
+ *
+ * In case the conffile has already been processed, sync the hash from an
+ * already configured package instance conffile.
+ *
+ * @param pkg The current package being configured.
+ * @param conff The current conffile being configured.
+ */
+static void
+deferred_configure_ghost_conffile(struct pkginfo *pkg, struct conffile *conff)
+{
+ struct pkginfo *otherpkg;
+ struct conffile *otherconff;
+
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->status <= PKG_STAT_HALFCONFIGURED)
+ continue;
+
+ for (otherconff = otherpkg->installed.conffiles; otherconff;
+ otherconff = otherconff->next) {
+ if (otherconff->obsolete || otherconff->remove_on_upgrade)
+ continue;
+
+ /* Check if we need to propagate the new hash from
+ * an already processed conffile in another package
+ * instance. */
+ if (strcmp(otherconff->name, conff->name) == 0) {
+ conff->hash = otherconff->hash;
+ modstatdb_note(pkg);
+ return;
+ }
+ }
+ }
+}
+
+static void
+deferred_configure_conffile(struct pkginfo *pkg, struct conffile *conff)
+{
+ struct fsys_namenode *usenode;
+ char currenthash[MD5HASHLEN + 1], newdisthash[MD5HASHLEN + 1];
+ int useredited, distedited;
+ enum conffopt what;
+ struct stat stab;
+ struct varbuf cdr = VARBUF_INIT, cdr2 = VARBUF_INIT;
+ char *cdr2rest;
+ int rc;
+
+ usenode = namenodetouse(fsys_hash_find_node(conff->name, FHFF_NOCOPY),
+ pkg, &pkg->installed);
+
+ rc = conffderef(pkg, &cdr, usenode->name);
+ if (rc == -1) {
+ conff->hash = EMPTYHASHFLAG;
+ return;
+ }
+ md5hash(pkg, currenthash, cdr.buf);
+
+ varbuf_reset(&cdr2);
+ varbuf_add_str(&cdr2, cdr.buf);
+ varbuf_end_str(&cdr2);
+ /* XXX: Make sure there's enough room for extensions. */
+ varbuf_grow(&cdr2, 50);
+ cdr2rest = cdr2.buf + strlen(cdr.buf);
+ /* From now on we can just strcpy(cdr2rest, extension); */
+
+ strcpy(cdr2rest, DPKGNEWEXT);
+ /* If the .dpkg-new file is no longer there, ignore this one. */
+ if (lstat(cdr2.buf, &stab)) {
+ if (errno == ENOENT) {
+ /* But, sync the conffile hash value from another
+ * package set instance. */
+ deferred_configure_ghost_conffile(pkg, conff);
+ return;
+ }
+ ohshite(_("unable to stat new distributed conffile '%.250s'"),
+ cdr2.buf);
+ }
+ md5hash(pkg, newdisthash, cdr2.buf);
+
+ /* Copy the permissions from the installed version to the new
+ * distributed version. */
+ if (!stat(cdr.buf, &stab))
+ file_copy_perms(cdr.buf, cdr2.buf);
+ else if (errno != ENOENT)
+ ohshite(_("unable to stat current installed conffile '%.250s'"),
+ cdr.buf);
+
+ /* Select what to do. */
+ if (strcmp(currenthash, newdisthash) == 0) {
+ /* They're both the same so there's no point asking silly
+ * questions. */
+ useredited = -1;
+ distedited = -1;
+ what = CFO_IDENTICAL;
+ } else if (strcmp(currenthash, NONEXISTENTFLAG) == 0 && in_force(FORCE_CONFF_MISS)) {
+ fprintf(stderr,
+ _("\n"
+ "Configuration file '%s', does not exist on system.\n"
+ "Installing new config file as you requested.\n"),
+ usenode->name);
+ what = CFO_NEW_CONFF;
+ useredited = -1;
+ distedited = -1;
+ } else if (strcmp(conff->hash, NEWCONFFILEFLAG) == 0) {
+ if (strcmp(currenthash, NONEXISTENTFLAG) == 0) {
+ what = CFO_NEW_CONFF;
+ useredited = -1;
+ distedited = -1;
+ } else {
+ useredited = 1;
+ distedited = 1;
+ what = conffoptcells[useredited][distedited] |
+ CFOF_IS_NEW;
+ }
+ } else {
+ useredited = strcmp(conff->hash, currenthash) != 0;
+ distedited = strcmp(conff->hash, newdisthash) != 0;
+
+ if (in_force(FORCE_CONFF_ASK) && useredited)
+ what = CFO_PROMPT_KEEP;
+ else
+ what = conffoptcells[useredited][distedited];
+
+ if (strcmp(currenthash, NONEXISTENTFLAG) == 0)
+ what |= CFOF_USER_DEL;
+ }
+
+ debug(dbg_conff,
+ "deferred_configure '%s' (= '%s') useredited=%d distedited=%d what=%o",
+ usenode->name, cdr.buf, useredited, distedited, what);
+
+ what = promptconfaction(pkg, usenode->name, cdr.buf, cdr2.buf,
+ useredited, distedited, what);
+
+ switch (what & ~(CFOF_IS_NEW | CFOF_USER_DEL)) {
+ case CFO_KEEP | CFOF_BACKUP:
+ strcpy(cdr2rest, DPKGOLDEXT);
+ if (unlink(cdr2.buf) && errno != ENOENT)
+ warning(_("%s: failed to remove old backup '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr2.buf,
+ strerror(errno));
+
+ varbuf_add_str(&cdr, DPKGDISTEXT);
+ varbuf_end_str(&cdr);
+ strcpy(cdr2rest, DPKGNEWEXT);
+ trig_path_activate(usenode, pkg);
+ if (rename(cdr2.buf, cdr.buf))
+ warning(_("%s: failed to rename '%.250s' to '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr2.buf, cdr.buf,
+ strerror(errno));
+ break;
+ case CFO_KEEP:
+ strcpy(cdr2rest, DPKGNEWEXT);
+ if (unlink(cdr2.buf))
+ warning(_("%s: failed to remove '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr2.buf,
+ strerror(errno));
+ break;
+ case CFO_INSTALL | CFOF_BACKUP:
+ strcpy(cdr2rest, DPKGDISTEXT);
+ if (unlink(cdr2.buf) && errno != ENOENT)
+ warning(_("%s: failed to remove old distributed version '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr2.buf,
+ strerror(errno));
+ strcpy(cdr2rest, DPKGOLDEXT);
+ if (unlink(cdr2.buf) && errno != ENOENT)
+ warning(_("%s: failed to remove '%.250s' (before overwrite): %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr2.buf,
+ strerror(errno));
+ if (!(what & CFOF_USER_DEL))
+ if (link(cdr.buf, cdr2.buf))
+ warning(_("%s: failed to link '%.250s' to '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr.buf,
+ cdr2.buf, strerror(errno));
+ /* Fall through. */
+ case CFO_INSTALL:
+ printf(_("Installing new version of config file %s ...\n"),
+ usenode->name);
+ /* Fall through. */
+ case CFO_NEW_CONFF:
+ strcpy(cdr2rest, DPKGNEWEXT);
+ trig_path_activate(usenode, pkg);
+ if (rename(cdr2.buf, cdr.buf))
+ ohshite(_("unable to install '%.250s' as '%.250s'"),
+ cdr2.buf, cdr.buf);
+ break;
+ default:
+ internerr("unknown conffopt '%d'", what);
+ }
+
+ conff->hash = nfstrsave(newdisthash);
+ modstatdb_note(pkg);
+
+ varbuf_destroy(&cdr);
+ varbuf_destroy(&cdr2);
+}
+
+/**
+ * Process the deferred configure package.
+ *
+ * @param pkg The package to act on.
+ */
+void
+deferred_configure(struct pkginfo *pkg)
+{
+ struct varbuf aemsgs = VARBUF_INIT;
+ struct conffile *conff;
+ struct pkginfo *otherpkg;
+ enum dep_check ok;
+
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ ohshit(_("no package named '%s' is installed, cannot configure"),
+ pkg_name(pkg, pnaw_nonambig));
+ if (pkg->status == PKG_STAT_INSTALLED)
+ ohshit(_("package %.250s is already installed and configured"),
+ pkg_name(pkg, pnaw_nonambig));
+ if (pkg->status != PKG_STAT_UNPACKED &&
+ pkg->status != PKG_STAT_HALFCONFIGURED)
+ ohshit(_("package %.250s is not ready for configuration\n"
+ " cannot configure (current status '%.250s')"),
+ pkg_name(pkg, pnaw_nonambig),
+ pkg_status_name(pkg));
+
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->status <= PKG_STAT_CONFIGFILES)
+ continue;
+
+ if (otherpkg->status < PKG_STAT_UNPACKED)
+ ohshit(_("package %s cannot be configured because "
+ "%s is not ready (current status '%s')"),
+ pkg_name(pkg, pnaw_always),
+ pkg_name(otherpkg, pnaw_always),
+ pkg_status_name(otherpkg));
+
+ if (dpkg_version_compare(&pkg->installed.version,
+ &otherpkg->installed.version))
+ ohshit(_("package %s %s cannot be configured because "
+ "%s is at a different version (%s)"),
+ pkg_name(pkg, pnaw_always),
+ versiondescribe(&pkg->installed.version,
+ vdew_nonambig),
+ pkg_name(otherpkg, pnaw_always),
+ versiondescribe(&otherpkg->installed.version,
+ vdew_nonambig));
+ }
+
+ if (dependtry >= DEPEND_TRY_CYCLES)
+ if (findbreakcycle(pkg))
+ sincenothing = 0;
+
+ ok = dependencies_ok(pkg, NULL, &aemsgs);
+ if (ok == DEP_CHECK_DEFER) {
+ varbuf_destroy(&aemsgs);
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->istobe = PKG_ISTOBE_INSTALLNEW;
+ enqueue_package(pkg);
+ return;
+ }
+
+ trigproc_reset_cycle();
+
+ /*
+ * At this point removal from the queue is confirmed. This
+ * represents irreversible progress wrt trigger cycles. Only
+ * packages in PKG_STAT_UNPACKED are automatically added to the
+ * configuration queue, and during configuration and trigger
+ * processing new packages can't enter into unpacked.
+ */
+
+ ok = breakses_ok(pkg, &aemsgs) ? ok : DEP_CHECK_HALT;
+ if (ok == DEP_CHECK_HALT) {
+ sincenothing = 0;
+ varbuf_end_str(&aemsgs);
+ notice(_("dependency problems prevent configuration of %s:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), aemsgs.buf);
+ varbuf_destroy(&aemsgs);
+ ohshit(_("dependency problems - leaving unconfigured"));
+ } else if (aemsgs.used) {
+ varbuf_end_str(&aemsgs);
+ notice(_("%s: dependency problems, but configuring anyway as you requested:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), aemsgs.buf);
+ }
+ varbuf_destroy(&aemsgs);
+ sincenothing = 0;
+
+ if (pkg->eflag & PKG_EFLAG_REINSTREQ)
+ forcibleerr(FORCE_REMOVE_REINSTREQ,
+ _("package is in a very bad inconsistent state; you should\n"
+ " reinstall it before attempting configuration"));
+
+ printf(_("Setting up %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ log_action("configure", pkg, &pkg->installed);
+
+ trig_activate_packageprocessing(pkg);
+
+ if (f_noact) {
+ pkg_set_status(pkg, PKG_STAT_INSTALLED);
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ return;
+ }
+
+ if (pkg->status == PKG_STAT_UNPACKED) {
+ debug(dbg_general, "deferred_configure updating conffiles");
+ /* This will not do at all the right thing with overridden
+ * conffiles or conffiles that are the ‘target’ of an override;
+ * all the references here would be to the ‘contested’
+ * filename, and in any case there'd only be one hash for both
+ * ‘versions’ of the conffile.
+ *
+ * Overriding conffiles is a silly thing to do anyway :-). */
+
+ modstatdb_note(pkg);
+
+ /* On entry, the ‘new’ version of each conffile has been
+ * unpacked as ‘*.dpkg-new’, and the ‘installed’ version is
+ * as-yet untouched in ‘*’. The hash of the ‘old distributed’
+ * version is in the conffiles data for the package. If
+ * ‘*.dpkg-new’ no longer exists we assume that we've
+ * already processed this one. */
+ for (conff = pkg->installed.conffiles; conff; conff = conff->next) {
+ if (conff->obsolete || conff->remove_on_upgrade)
+ continue;
+ deferred_configure_conffile(pkg, conff);
+ }
+
+ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED);
+ }
+
+ if (pkg->status != PKG_STAT_HALFCONFIGURED)
+ internerr("package %s in state %s, instead of half-configured",
+ pkg_name(pkg, pnaw_always), pkg_status_name(pkg));
+
+ modstatdb_note(pkg);
+
+ maintscript_postinst(pkg, "configure",
+ dpkg_version_is_informative(&pkg->configversion) ?
+ versiondescribe(&pkg->configversion,
+ vdew_nonambig) : "",
+ NULL);
+
+ pkg_reset_eflags(pkg);
+ pkg->trigpend_head = NULL;
+ post_postinst_tasks(pkg, PKG_STAT_INSTALLED);
+}
+
+/**
+ * Dereference a file by following all possibly used symlinks.
+ *
+ * @param[in] pkg The package to act on.
+ * @param[out] result The dereference conffile path.
+ * @param[in] in The conffile path to dereference.
+ *
+ * @return An error code for the operation.
+ * @retval 0 Everything went ok.
+ * @retval -1 Otherwise.
+ */
+int
+conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in)
+{
+ static struct varbuf target = VARBUF_INIT;
+ struct stat stab;
+ ssize_t r;
+ int loopprotect;
+
+ varbuf_reset(result);
+ varbuf_add_str(result, dpkg_fsys_get_dir());
+ varbuf_add_str(result, in);
+ varbuf_end_str(result);
+
+ loopprotect = 0;
+
+ for (;;) {
+ debug(dbg_conffdetail, "conffderef in='%s' current working='%s'",
+ in, result->buf);
+ if (lstat(result->buf, &stab)) {
+ if (errno != ENOENT)
+ warning(_("%s: unable to stat config file '%s'\n"
+ " (= '%s'): %s"),
+ pkg_name(pkg, pnaw_nonambig), in,
+ result->buf, strerror(errno));
+ debug(dbg_conffdetail, "conffderef nonexistent");
+ return 0;
+ } else if (S_ISREG(stab.st_mode)) {
+ debug(dbg_conff, "conffderef in='%s' result='%s'",
+ in, result->buf);
+ return 0;
+ } else if (S_ISLNK(stab.st_mode)) {
+ debug(dbg_conffdetail, "conffderef symlink loopprotect=%d",
+ loopprotect);
+ if (loopprotect++ >= 25) {
+ warning(_("%s: config file '%s' is a circular link\n"
+ " (= '%s')"),
+ pkg_name(pkg, pnaw_nonambig), in,
+ result->buf);
+ return -1;
+ }
+
+ varbuf_reset(&target);
+ varbuf_grow(&target, stab.st_size + 1);
+ r = readlink(result->buf, target.buf, target.size);
+ if (r < 0) {
+ warning(_("%s: unable to readlink conffile '%s'\n"
+ " (= '%s'): %s"),
+ pkg_name(pkg, pnaw_nonambig), in,
+ result->buf, strerror(errno));
+ return -1;
+ } else if (r != stab.st_size) {
+ warning(_("symbolic link '%.250s' size has "
+ "changed from %jd to %zd"),
+ result->buf, (intmax_t)stab.st_size, r);
+ /* If the returned size is smaller, let's
+ * proceed, otherwise error out. */
+ if (r > stab.st_size)
+ return -1;
+ }
+ varbuf_trunc(&target, r);
+ varbuf_end_str(&target);
+
+ debug(dbg_conffdetail,
+ "conffderef readlink gave %zd, '%s'",
+ r, target.buf);
+
+ if (target.buf[0] == '/') {
+ varbuf_reset(result);
+ varbuf_add_str(result, dpkg_fsys_get_dir());
+ debug(dbg_conffdetail,
+ "conffderef readlink absolute");
+ } else {
+ for (r = result->used - 1; r > 0 && result->buf[r] != '/'; r--)
+ ;
+ if (r < 0) {
+ warning(_("%s: conffile '%.250s' resolves to degenerate filename\n"
+ " ('%s' is a symlink to '%s')"),
+ pkg_name(pkg, pnaw_nonambig),
+ in, result->buf, target.buf);
+ return -1;
+ }
+ if (result->buf[r] == '/')
+ r++;
+ varbuf_trunc(result, r);
+ debug(dbg_conffdetail,
+ "conffderef readlink relative to '%.*s'",
+ (int)result->used, result->buf);
+ }
+ varbuf_add_buf(result, target.buf, target.used);
+ varbuf_end_str(result);
+ } else {
+ warning(_("%s: conffile '%.250s' is not a plain file or symlink (= '%s')"),
+ pkg_name(pkg, pnaw_nonambig), in, result->buf);
+ return -1;
+ }
+ }
+}
+
+/**
+ * Generate a file contents MD5 hash.
+ *
+ * The caller is responsible for providing a buffer for the hash result
+ * at least MD5HASHLEN + 1 characters long.
+ *
+ * @param[in] pkg The package to act on.
+ * @param[out] hashbuf The buffer to store the generated hash.
+ * @param[in] fn The filename.
+ */
+void
+md5hash(struct pkginfo *pkg, char *hashbuf, const char *fn)
+{
+ struct dpkg_error err;
+ static int fd;
+
+ fd = open(fn, O_RDONLY);
+
+ if (fd >= 0) {
+ push_cleanup(cu_closefd, ehflag_bombout, 1, &fd);
+ if (fd_md5(fd, hashbuf, -1, &err) < 0)
+ ohshit(_("cannot compute MD5 digest for file '%s': %s"),
+ fn, err.str);
+ pop_cleanup(ehflag_normaltidy); /* fd = open(cdr.buf) */
+ close(fd);
+ } else if (errno == ENOENT) {
+ strcpy(hashbuf, NONEXISTENTFLAG);
+ } else {
+ warning(_("%s: unable to open %s to compute its digest: %s"),
+ pkg_name(pkg, pnaw_nonambig), fn, strerror(errno));
+ strcpy(hashbuf, EMPTYHASHFLAG);
+ }
+}
diff --git a/src/main/depcon.c b/src/main/depcon.c
new file mode 100644
index 0000000..2990caa
--- /dev/null
+++ b/src/main/depcon.c
@@ -0,0 +1,704 @@
+/*
+ * dpkg - main program for package management
+ * depcon.c - dependency and conflict checking
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2014 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+struct deppossi_pkg_iterator {
+ struct deppossi *possi;
+ struct pkginfo *pkg_next;
+ enum which_pkgbin which_pkgbin;
+};
+
+struct deppossi_pkg_iterator *
+deppossi_pkg_iter_new(struct deppossi *possi, enum which_pkgbin wpb)
+{
+ struct deppossi_pkg_iterator *iter;
+
+ iter = m_malloc(sizeof(*iter));
+ iter->possi = possi;
+ iter->pkg_next = &possi->ed->pkg;
+ iter->which_pkgbin = wpb;
+
+ return iter;
+}
+
+struct pkginfo *
+deppossi_pkg_iter_next(struct deppossi_pkg_iterator *iter)
+{
+ struct pkginfo *pkg_cur;
+ struct pkgbin *pkgbin;
+
+ while ((pkg_cur = iter->pkg_next)) {
+ iter->pkg_next = pkg_cur->arch_next;
+
+ switch (iter->which_pkgbin) {
+ case wpb_installed:
+ pkgbin = &pkg_cur->installed;
+ break;
+ case wpb_available:
+ pkgbin = &pkg_cur->available;
+ break;
+ case wpb_by_istobe:
+ if (pkg_cur->clientdata &&
+ pkg_cur->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)
+ pkgbin = &pkg_cur->available;
+ else
+ pkgbin = &pkg_cur->installed;
+ break;
+ default:
+ internerr("unknown which_pkgbin %d", iter->which_pkgbin);
+ }
+
+ if (archsatisfied(pkgbin, iter->possi))
+ return pkg_cur;
+ }
+
+ return NULL;
+}
+
+void
+deppossi_pkg_iter_free(struct deppossi_pkg_iterator *iter)
+{
+ free(iter);
+}
+
+struct cyclesofarlink {
+ struct cyclesofarlink *prev;
+ struct pkginfo *pkg;
+ struct deppossi *possi;
+};
+
+static bool findbreakcyclerecursive(struct pkginfo *pkg,
+ struct cyclesofarlink *sofar);
+
+static bool
+foundcyclebroken(struct cyclesofarlink *thislink, struct cyclesofarlink *sofar,
+ struct pkginfo *dependedon, struct deppossi *possi)
+{
+ struct cyclesofarlink *sol;
+
+ if(!possi)
+ return false;
+
+ /* We're investigating the dependency ‘possi’ to see if it
+ * is part of a loop. To this end we look to see whether the
+ * depended-on package is already one of the packages whose
+ * dependencies we're searching. */
+ for (sol = sofar; sol && sol->pkg != dependedon; sol = sol->prev);
+
+ /* If not, we do a recursive search on it to see what we find. */
+ if (!sol)
+ return findbreakcyclerecursive(dependedon, thislink);
+
+ debug(dbg_depcon,"found cycle");
+ /* Right, we now break one of the links. We prefer to break
+ * a dependency of a package without a postinst script, as
+ * this is a null operation. If this is not possible we break
+ * the other link in the recursive calling tree which mentions
+ * this package (this being the first package involved in the
+ * cycle). It doesn't particularly matter which we pick, but if
+ * we break the earliest dependency we came across we may be
+ * able to do something straight away when findbreakcycle returns. */
+ sofar= thislink;
+ for (sol = sofar; !(sol != sofar && sol->pkg == dependedon); sol = sol->prev) {
+ if (!pkg_infodb_has_file(sol->pkg, &sol->pkg->installed, POSTINSTFILE))
+ break;
+ }
+
+ /* Now we have either a package with no postinst, or the other
+ * occurrence of the current package in the list. */
+ sol->possi->cyclebreak = true;
+
+ debug(dbg_depcon, "cycle broken at %s -> %s",
+ pkg_name(sol->possi->up->up, pnaw_always), sol->possi->ed->name);
+
+ return true;
+}
+
+/**
+ * Cycle breaking works recursively down the package dependency tree.
+ *
+ * ‘sofar’ is the list of packages we've descended down already - if we
+ * encounter any of its packages again in a dependency we have found a cycle.
+ */
+static bool
+findbreakcyclerecursive(struct pkginfo *pkg, struct cyclesofarlink *sofar)
+{
+ struct cyclesofarlink thislink, *sol;
+ struct dependency *dep;
+ struct deppossi *possi, *providelink;
+ struct pkginfo *provider, *pkg_pos;
+
+ if (pkg->clientdata->color == PKG_CYCLE_BLACK)
+ return false;
+ pkg->clientdata->color = PKG_CYCLE_GRAY;
+
+ if (debug_has_flag(dbg_depcondetail)) {
+ struct varbuf str_pkgs = VARBUF_INIT;
+
+ for (sol = sofar; sol; sol = sol->prev) {
+ varbuf_add_str(&str_pkgs, " <- ");
+ varbuf_add_pkgbin_name(&str_pkgs, sol->pkg, &sol->pkg->installed, pnaw_nonambig);
+ }
+ varbuf_end_str(&str_pkgs);
+ debug(dbg_depcondetail, "findbreakcyclerecursive %s %s",
+ pkg_name(pkg, pnaw_always), str_pkgs.buf);
+ varbuf_destroy(&str_pkgs);
+ }
+ thislink.pkg= pkg;
+ thislink.prev = sofar;
+ thislink.possi = NULL;
+ for (dep= pkg->installed.depends; dep; dep= dep->next) {
+ if (dep->type != dep_depends && dep->type != dep_predepends) continue;
+ for (possi= dep->list; possi; possi= possi->next) {
+ struct deppossi_pkg_iterator *possi_iter;
+
+ /* Don't find the same cycles again. */
+ if (possi->cyclebreak) continue;
+ thislink.possi= possi;
+
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_installed);
+ while ((pkg_pos = deppossi_pkg_iter_next(possi_iter)))
+ if (foundcyclebroken(&thislink, sofar, pkg_pos, possi)) {
+ deppossi_pkg_iter_free(possi_iter);
+ return true;
+ }
+ deppossi_pkg_iter_free(possi_iter);
+
+ /* Right, now we try all the providers ... */
+ for (providelink = possi->ed->depended.installed;
+ providelink;
+ providelink = providelink->rev_next) {
+ if (providelink->up->type != dep_provides) continue;
+ provider= providelink->up->up;
+ if (provider->clientdata->istobe == PKG_ISTOBE_NORMAL)
+ continue;
+ /* We don't break things at ‘provides’ links, so ‘possi’ is
+ * still the one we use. */
+ if (foundcyclebroken(&thislink, sofar, provider, possi))
+ return true;
+ }
+ }
+ }
+ /* Nope, we didn't find a cycle to break. */
+ pkg->clientdata->color = PKG_CYCLE_BLACK;
+ return false;
+}
+
+bool
+findbreakcycle(struct pkginfo *pkg)
+{
+ struct pkg_hash_iter *iter;
+ struct pkginfo *tpkg;
+
+ /* Clear the visited flag of all packages before we traverse them. */
+ iter = pkg_hash_iter_new();
+ while ((tpkg = pkg_hash_iter_next_pkg(iter))) {
+ ensure_package_clientdata(tpkg);
+ tpkg->clientdata->color = PKG_CYCLE_WHITE;
+ }
+ pkg_hash_iter_free(iter);
+
+ return findbreakcyclerecursive(pkg, NULL);
+}
+
+void describedepcon(struct varbuf *addto, struct dependency *dep) {
+ struct varbuf depstr = VARBUF_INIT;
+
+ varbufdependency(&depstr, dep);
+ varbuf_end_str(&depstr);
+
+ switch (dep->type) {
+ case dep_depends:
+ varbuf_printf(addto, _("%s depends on %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_predepends:
+ varbuf_printf(addto, _("%s pre-depends on %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_recommends:
+ varbuf_printf(addto, _("%s recommends %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_suggests:
+ varbuf_printf(addto, _("%s suggests %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_breaks:
+ varbuf_printf(addto, _("%s breaks %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_conflicts:
+ varbuf_printf(addto, _("%s conflicts with %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ case dep_enhances:
+ varbuf_printf(addto, _("%s enhances %s"),
+ pkg_name(dep->up, pnaw_nonambig), depstr.buf);
+ break;
+ default:
+ internerr("unknown deptype '%d'", dep->type);
+ }
+
+ varbuf_destroy(&depstr);
+}
+
+/*
+ * *whynot must already have been initialized; it need not be
+ * empty though - it will be reset before use.
+ *
+ * If depisok returns false for ‘not OK’ it will contain a description,
+ * newline-terminated BUT NOT NUL-TERMINATED, of the reason.
+ *
+ * If depisok returns true it will contain garbage.
+ * allowunconfigd should be non-zero during the ‘Pre-Depends’ checking
+ * before a package is unpacked, when it is sufficient for the package
+ * to be unpacked provided that both the unpacked and previously-configured
+ * versions are acceptable.
+ *
+ * On false return (‘not OK’), *canfixbyremove refers to a package which
+ * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix
+ * the problem. Caller may pass NULL for canfixbyremove and need not
+ * initialize *canfixbyremove.
+ *
+ * On false return (‘not OK’), *canfixbytrigaw refers to a package which
+ * can fix the problem if all the packages listed in Triggers-Awaited have
+ * their triggers processed. Caller may pass NULL for canfixbytrigaw and
+ * need not initialize *canfixbytrigaw.
+ */
+bool
+depisok(struct dependency *dep, struct varbuf *whynot,
+ struct pkginfo **canfixbyremove, struct pkginfo **canfixbytrigaw,
+ bool allowunconfigd)
+{
+ struct deppossi *possi;
+ struct deppossi *provider;
+ struct pkginfo *pkg_pos;
+ int nconflicts;
+
+ /* Use this buffer so that when internationalization comes along we
+ * don't have to rewrite the code completely, only redo the sprintf strings
+ * (assuming we have the fancy argument-number-specifiers).
+ * Allow 250x3 for package names, versions, &c, + 250 for ourselves. */
+ char linebuf[1024];
+
+ if (dep->type != dep_depends &&
+ dep->type != dep_predepends &&
+ dep->type != dep_breaks &&
+ dep->type != dep_conflicts &&
+ dep->type != dep_recommends &&
+ dep->type != dep_suggests &&
+ dep->type != dep_enhances)
+ internerr("unknown dependency type %d", dep->type);
+
+ if (canfixbyremove)
+ *canfixbyremove = NULL;
+ if (canfixbytrigaw)
+ *canfixbytrigaw = NULL;
+
+ /* The dependency is always OK if we're trying to remove the depend*ing*
+ * package. */
+ switch (dep->up->clientdata->istobe) {
+ case PKG_ISTOBE_REMOVE:
+ case PKG_ISTOBE_DECONFIGURE:
+ return true;
+ case PKG_ISTOBE_NORMAL:
+ /* Only installed packages can be made dependency problems. */
+ switch (dep->up->status) {
+ case PKG_STAT_INSTALLED:
+ case PKG_STAT_TRIGGERSPENDING:
+ case PKG_STAT_TRIGGERSAWAITED:
+ break;
+ case PKG_STAT_HALFCONFIGURED:
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_HALFINSTALLED:
+ if (dep->type == dep_predepends ||
+ dep->type == dep_conflicts ||
+ dep->type == dep_breaks)
+ break;
+ /* Fall through. */
+ case PKG_STAT_CONFIGFILES:
+ case PKG_STAT_NOTINSTALLED:
+ return true;
+ default:
+ internerr("unknown status depending '%d'", dep->up->status);
+ }
+ break;
+ case PKG_ISTOBE_INSTALLNEW:
+ case PKG_ISTOBE_PREINSTALL:
+ break;
+ default:
+ internerr("unknown istobe depending '%d'", dep->up->clientdata->istobe);
+ }
+
+ /* Describe the dependency, in case we have to moan about it. */
+ varbuf_reset(whynot);
+ varbuf_add_char(whynot, ' ');
+ describedepcon(whynot, dep);
+ varbuf_add_char(whynot, '\n');
+
+ /* TODO: Check dep_enhances as well. */
+ if (dep->type == dep_depends || dep->type == dep_predepends ||
+ dep->type == dep_recommends || dep->type == dep_suggests ) {
+ /* Go through the alternatives. As soon as we find one that
+ * we like, we return ‘true’ straight away. Otherwise, when we get to
+ * the end we'll have accumulated all the reasons in whynot and
+ * can return ‘false’. */
+
+ for (possi= dep->list; possi; possi= possi->next) {
+ struct deppossi_pkg_iterator *possi_iter;
+
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe);
+ while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
+ switch (pkg_pos->clientdata->istobe) {
+ case PKG_ISTOBE_REMOVE:
+ sprintf(linebuf, _(" %.250s is to be removed.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig));
+ break;
+ case PKG_ISTOBE_DECONFIGURE:
+ sprintf(linebuf, _(" %.250s is to be deconfigured.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig));
+ break;
+ case PKG_ISTOBE_INSTALLNEW:
+ if (versionsatisfied(&pkg_pos->available, possi)) {
+ deppossi_pkg_iter_free(possi_iter);
+ return true;
+ }
+ sprintf(linebuf, _(" %.250s is to be installed, but is version "
+ "%.250s.\n"),
+ pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig),
+ versiondescribe(&pkg_pos->available.version, vdew_nonambig));
+ break;
+ case PKG_ISTOBE_NORMAL:
+ case PKG_ISTOBE_PREINSTALL:
+ switch (pkg_pos->status) {
+ case PKG_STAT_INSTALLED:
+ case PKG_STAT_TRIGGERSPENDING:
+ if (versionsatisfied(&pkg_pos->installed, possi)) {
+ deppossi_pkg_iter_free(possi_iter);
+ return true;
+ }
+ sprintf(linebuf, _(" %.250s is installed, but is version "
+ "%.250s.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig),
+ versiondescribe(&pkg_pos->installed.version, vdew_nonambig));
+ break;
+ case PKG_STAT_NOTINSTALLED:
+ /* Don't say anything about this yet - it might be a virtual package.
+ * Later on, if nothing has put anything in linebuf, we know that it
+ * isn't and issue a diagnostic then. */
+ *linebuf = '\0';
+ break;
+ case PKG_STAT_TRIGGERSAWAITED:
+ if (canfixbytrigaw && versionsatisfied(&pkg_pos->installed, possi))
+ *canfixbytrigaw = pkg_pos;
+ /* Fall through. */
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_HALFCONFIGURED:
+ if (allowunconfigd) {
+ if (!dpkg_version_is_informative(&pkg_pos->configversion)) {
+ sprintf(linebuf, _(" %.250s is unpacked, but has never been "
+ "configured.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig));
+ break;
+ } else if (!versionsatisfied(&pkg_pos->installed, possi)) {
+ sprintf(linebuf, _(" %.250s is unpacked, but is version "
+ "%.250s.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig),
+ versiondescribe(&pkg_pos->installed.version,
+ vdew_nonambig));
+ break;
+ } else if (!dpkg_version_relate(&pkg_pos->configversion,
+ possi->verrel,
+ &possi->version)) {
+ sprintf(linebuf, _(" %.250s latest configured version is "
+ "%.250s.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig),
+ versiondescribe(&pkg_pos->configversion, vdew_nonambig));
+ break;
+ } else {
+ deppossi_pkg_iter_free(possi_iter);
+ return true;
+ }
+ }
+ /* Fall through. */
+ default:
+ sprintf(linebuf, _(" %.250s is %s.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig),
+ gettext(statusstrings[pkg_pos->status]));
+ break;
+ }
+ break;
+ default:
+ internerr("unknown istobe depended '%d'", pkg_pos->clientdata->istobe);
+ }
+ varbuf_add_str(whynot, linebuf);
+ }
+ deppossi_pkg_iter_free(possi_iter);
+
+ /* See if the package we're about to install Provides it. */
+ for (provider = possi->ed->depended.available;
+ provider;
+ provider = provider->rev_next) {
+ if (provider->up->type != dep_provides) continue;
+ if (!pkg_virtual_deppossi_satisfied(possi, provider))
+ continue;
+ if (provider->up->up->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)
+ return true;
+ }
+
+ /* Now look at the packages already on the system. */
+ for (provider = possi->ed->depended.installed;
+ provider;
+ provider = provider->rev_next) {
+ if (provider->up->type != dep_provides) continue;
+ if (!pkg_virtual_deppossi_satisfied(possi, provider))
+ continue;
+
+ switch (provider->up->up->clientdata->istobe) {
+ case PKG_ISTOBE_INSTALLNEW:
+ /* Don't pay any attention to the Provides field of the
+ * currently-installed version of the package we're trying
+ * to install. We dealt with that by using the available
+ * information above. */
+ continue;
+ case PKG_ISTOBE_REMOVE:
+ sprintf(linebuf, _(" %.250s provides %.250s but is to be removed.\n"),
+ pkg_name(provider->up->up, pnaw_nonambig),
+ possi->ed->name);
+ break;
+ case PKG_ISTOBE_DECONFIGURE:
+ sprintf(linebuf, _(" %.250s provides %.250s but is to be deconfigured.\n"),
+ pkg_name(provider->up->up, pnaw_nonambig),
+ possi->ed->name);
+ break;
+ case PKG_ISTOBE_NORMAL:
+ case PKG_ISTOBE_PREINSTALL:
+ if (provider->up->up->status == PKG_STAT_INSTALLED ||
+ provider->up->up->status == PKG_STAT_TRIGGERSPENDING)
+ return true;
+ if (provider->up->up->status == PKG_STAT_TRIGGERSAWAITED)
+ *canfixbytrigaw = provider->up->up;
+ sprintf(linebuf, _(" %.250s provides %.250s but is %s.\n"),
+ pkg_name(provider->up->up, pnaw_nonambig),
+ possi->ed->name,
+ gettext(statusstrings[provider->up->up->status]));
+ break;
+ default:
+ internerr("unknown istobe provider '%d'",
+ provider->up->up->clientdata->istobe);
+ }
+ varbuf_add_str(whynot, linebuf);
+ }
+
+ if (!*linebuf) {
+ /* If the package wasn't installed at all, and we haven't said
+ * yet why this isn't satisfied, we should say so now. */
+ sprintf(linebuf, _(" %.250s is not installed.\n"), possi->ed->name);
+ varbuf_add_str(whynot, linebuf);
+ }
+ }
+
+ return false;
+ } else {
+ /* It's conflicts or breaks. There's only one main alternative,
+ * but we also have to consider Providers. We return ‘false’ as soon
+ * as we find something that matches the conflict, and only describe
+ * it then. If we get to the end without finding anything we return
+ * ‘true’. */
+
+ possi= dep->list;
+ nconflicts= 0;
+
+ if (possi->ed != possi->up->up->set) {
+ struct deppossi_pkg_iterator *possi_iter;
+
+ /* If the package conflicts with or breaks itself it must mean
+ * other packages which provide the same virtual name. We
+ * therefore don't look at the real package and go on to the
+ * virtual ones. */
+
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe);
+ while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
+ switch (pkg_pos->clientdata->istobe) {
+ case PKG_ISTOBE_REMOVE:
+ break;
+ case PKG_ISTOBE_INSTALLNEW:
+ if (!versionsatisfied(&pkg_pos->available, possi))
+ break;
+ sprintf(linebuf, _(" %.250s (version %.250s) is to be installed.\n"),
+ pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig),
+ versiondescribe(&pkg_pos->available.version, vdew_nonambig));
+ varbuf_add_str(whynot, linebuf);
+ if (!canfixbyremove) {
+ deppossi_pkg_iter_free(possi_iter);
+ return false;
+ }
+ nconflicts++;
+ *canfixbyremove = pkg_pos;
+ break;
+ case PKG_ISTOBE_DECONFIGURE:
+ if (dep->type == dep_breaks)
+ break; /* Already deconfiguring this. */
+ /* Fall through. */
+ case PKG_ISTOBE_NORMAL:
+ case PKG_ISTOBE_PREINSTALL:
+ switch (pkg_pos->status) {
+ case PKG_STAT_NOTINSTALLED:
+ case PKG_STAT_CONFIGFILES:
+ break;
+ case PKG_STAT_HALFINSTALLED:
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_HALFCONFIGURED:
+ if (dep->type == dep_breaks)
+ break; /* No problem. */
+ /* Fall through. */
+ case PKG_STAT_INSTALLED:
+ case PKG_STAT_TRIGGERSPENDING:
+ case PKG_STAT_TRIGGERSAWAITED:
+ if (!versionsatisfied(&pkg_pos->installed, possi))
+ break;
+ sprintf(linebuf, _(" %.250s (version %.250s) is present and %s.\n"),
+ pkg_name(pkg_pos, pnaw_nonambig),
+ versiondescribe(&pkg_pos->installed.version, vdew_nonambig),
+ gettext(statusstrings[pkg_pos->status]));
+ varbuf_add_str(whynot, linebuf);
+ if (!canfixbyremove) {
+ deppossi_pkg_iter_free(possi_iter);
+ return false;
+ }
+ nconflicts++;
+ *canfixbyremove = pkg_pos;
+ }
+ break;
+ default:
+ internerr("unknown istobe conflict '%d'", pkg_pos->clientdata->istobe);
+ }
+ }
+ deppossi_pkg_iter_free(possi_iter);
+ }
+
+ /* See if the package we're about to install Provides it. */
+ for (provider = possi->ed->depended.available;
+ provider;
+ provider = provider->rev_next) {
+ if (provider->up->type != dep_provides) continue;
+ if (provider->up->up->clientdata->istobe != PKG_ISTOBE_INSTALLNEW)
+ continue;
+ if (provider->up->up->set == dep->up->set)
+ continue; /* Conflicts and provides the same. */
+ if (!pkg_virtual_deppossi_satisfied(possi, provider))
+ continue;
+ sprintf(linebuf, _(" %.250s provides %.250s and is to be installed.\n"),
+ pkgbin_name(provider->up->up, &provider->up->up->available,
+ pnaw_nonambig), possi->ed->name);
+ varbuf_add_str(whynot, linebuf);
+ /* We can't remove the one we're about to install: */
+ if (canfixbyremove)
+ *canfixbyremove = NULL;
+ return false;
+ }
+
+ /* Now look at the packages already on the system. */
+ for (provider = possi->ed->depended.installed;
+ provider;
+ provider = provider->rev_next) {
+ if (provider->up->type != dep_provides) continue;
+
+ if (provider->up->up->set == dep->up->set)
+ continue; /* Conflicts and provides the same. */
+
+ if (!pkg_virtual_deppossi_satisfied(possi, provider))
+ continue;
+
+ switch (provider->up->up->clientdata->istobe) {
+ case PKG_ISTOBE_INSTALLNEW:
+ /* Don't pay any attention to the Provides field of the
+ * currently-installed version of the package we're trying
+ * to install. We dealt with that package by using the
+ * available information above. */
+ continue;
+ case PKG_ISTOBE_REMOVE:
+ continue;
+ case PKG_ISTOBE_DECONFIGURE:
+ if (dep->type == dep_breaks)
+ continue; /* Already deconfiguring. */
+ /* Fall through. */
+ case PKG_ISTOBE_NORMAL:
+ case PKG_ISTOBE_PREINSTALL:
+ switch (provider->up->up->status) {
+ case PKG_STAT_NOTINSTALLED:
+ case PKG_STAT_CONFIGFILES:
+ continue;
+ case PKG_STAT_HALFINSTALLED:
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_HALFCONFIGURED:
+ if (dep->type == dep_breaks)
+ break; /* No problem. */
+ /* Fall through. */
+ case PKG_STAT_INSTALLED:
+ case PKG_STAT_TRIGGERSPENDING:
+ case PKG_STAT_TRIGGERSAWAITED:
+ sprintf(linebuf,
+ _(" %.250s provides %.250s and is present and %s.\n"),
+ pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name,
+ gettext(statusstrings[provider->up->up->status]));
+ varbuf_add_str(whynot, linebuf);
+ if (!canfixbyremove)
+ return false;
+ nconflicts++;
+ *canfixbyremove= provider->up->up;
+ break;
+ }
+ break;
+ default:
+ internerr("unknown istobe conflict provider '%d'",
+ provider->up->up->clientdata->istobe);
+ }
+ }
+
+ if (!nconflicts)
+ return true;
+ if (nconflicts > 1)
+ *canfixbyremove = NULL;
+ return false;
+
+ } /* if (dependency) {...} else {...} */
+}
diff --git a/src/main/enquiry.c b/src/main/enquiry.c
new file mode 100644
index 0000000..cc605c2
--- /dev/null
+++ b/src/main/enquiry.c
@@ -0,0 +1,906 @@
+/*
+ * dpkg - main program for package management
+ * enquiry.c - status enquiry and listing options
+ *
+ * Copyright © 1995,1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2016 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
+#include <dpkg/pkg-array.h>
+#include <dpkg/pkg-show.h>
+#include <dpkg/triglib.h>
+#include <dpkg/string.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+struct audit_problem {
+ bool (*check)(struct pkginfo *, const struct audit_problem *problem);
+ union {
+ int number;
+ const char *string;
+ } value;
+ const char *explanation;
+};
+
+static bool
+audit_reinstreq(struct pkginfo *pkg, const struct audit_problem *problem)
+{
+ return pkg->eflag & PKG_EFLAG_REINSTREQ;
+}
+
+static bool
+audit_status(struct pkginfo *pkg, const struct audit_problem *problem)
+{
+ if (pkg->eflag & PKG_EFLAG_REINSTREQ)
+ return false;
+ return (int)pkg->status == problem->value.number;
+}
+
+static bool
+audit_infofile(struct pkginfo *pkg, const struct audit_problem *problem)
+{
+ if (pkg->status < PKG_STAT_HALFINSTALLED)
+ return false;
+ return !pkg_infodb_has_file(pkg, &pkg->installed, problem->value.string);
+}
+
+static bool
+audit_arch(struct pkginfo *pkg, const struct audit_problem *problem)
+{
+ if (pkg->status < PKG_STAT_HALFINSTALLED)
+ return false;
+ return pkg->installed.arch->type == (enum dpkg_arch_type)problem->value.number;
+}
+
+static const struct audit_problem audit_problems[] = {
+ {
+ .check = audit_reinstreq,
+ .value.number = 0,
+ .explanation = N_(
+ "The following packages are in a mess due to serious problems during\n"
+ "installation. They must be reinstalled for them (and any packages\n"
+ "that depend on them) to function properly:\n")
+ }, {
+ .check = audit_status,
+ .value.number = PKG_STAT_UNPACKED,
+ .explanation = N_(
+ "The following packages have been unpacked but not yet configured.\n"
+ "They must be configured using dpkg --configure or the configure\n"
+ "menu option in dselect for them to work:\n")
+ }, {
+ .check = audit_status,
+ .value.number = PKG_STAT_HALFCONFIGURED,
+ .explanation = N_(
+ "The following packages are only half configured, probably due to problems\n"
+ "configuring them the first time. The configuration should be retried using\n"
+ "dpkg --configure <package> or the configure menu option in dselect:\n")
+ }, {
+ .check = audit_status,
+ .value.number = PKG_STAT_HALFINSTALLED,
+ .explanation = N_(
+ "The following packages are only half installed, due to problems during\n"
+ "installation. The installation can probably be completed by retrying it;\n"
+ "the packages can be removed using dselect or dpkg --remove:\n")
+ }, {
+ .check = audit_status,
+ .value.number = PKG_STAT_TRIGGERSAWAITED,
+ .explanation = N_(
+ "The following packages are awaiting processing of triggers that they\n"
+ "have activated in other packages. This processing can be requested using\n"
+ "dselect or dpkg --configure --pending (or dpkg --triggers-only):\n")
+ }, {
+ .check = audit_status,
+ .value.number = PKG_STAT_TRIGGERSPENDING,
+ .explanation = N_(
+ "The following packages have been triggered, but the trigger processing\n"
+ "has not yet been done. Trigger processing can be requested using\n"
+ "dselect or dpkg --configure --pending (or dpkg --triggers-only):\n")
+ }, {
+ .check = audit_infofile,
+ .value.string = LISTFILE,
+ .explanation = N_(
+ "The following packages are missing the list control file in the\n"
+ "database, they need to be reinstalled:\n")
+ }, {
+ .check = audit_infofile,
+ .value.string = HASHFILE,
+ .explanation = N_(
+ "The following packages are missing the md5sums control file in the\n"
+ "database, they need to be reinstalled:\n")
+ }, {
+ .check = audit_arch,
+ .value.number = DPKG_ARCH_EMPTY,
+ .explanation = N_("The following packages do not have an architecture:\n")
+ }, {
+ .check = audit_arch,
+ .value.number = DPKG_ARCH_ILLEGAL,
+ .explanation = N_("The following packages have an illegal architecture:\n")
+ }, {
+ .check = audit_arch,
+ .value.number = DPKG_ARCH_UNKNOWN,
+ .explanation = N_(
+ "The following packages have an unknown foreign architecture, which will\n"
+ "cause dependency issues on front-ends. This can be fixed by registering\n"
+ "the foreign architecture with dpkg --add-architecture:\n")
+ }, {
+ .check = NULL
+ }
+};
+
+static void describebriefly(struct pkginfo *pkg) {
+ int maxl, l;
+ const char *pdesc;
+
+ maxl= 57;
+ l= strlen(pkg->set->name);
+ if (l>20) maxl -= (l-20);
+
+ pdesc = pkgbin_synopsis(pkg, &pkg->installed, &l);
+ l = min(l, maxl);
+
+ printf(" %-20s %.*s\n", pkg_name(pkg, pnaw_nonambig), l, pdesc);
+}
+
+static struct pkginfo *
+pkg_array_mapper(const char *name)
+{
+ struct pkginfo *pkg;
+
+ pkg = dpkg_options_parse_pkgname(cipaction, name);
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ notice(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig));
+
+ return pkg;
+}
+
+int
+audit(const char *const *argv)
+{
+ const struct audit_problem *problem;
+ struct pkg_array array;
+ bool head_running = false;
+ int i;
+
+ modstatdb_open(msdbrw_readonly);
+
+ if (!*argv)
+ pkg_array_init_from_hash(&array);
+ else
+ pkg_array_init_from_names(&array, pkg_array_mapper, (const char **)argv);
+
+ pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
+
+ for (problem = audit_problems; problem->check; problem++) {
+ bool head = false;
+
+ for (i = 0; i < array.n_pkgs; i++) {
+ struct pkginfo *pkg = array.pkgs[i];
+
+ if (!problem->check(pkg, problem))
+ continue;
+ if (!head_running) {
+ if (modstatdb_is_locked())
+ puts(_(
+"Another process has locked the database for writing, and might currently be\n"
+"modifying it, some of the following problems might just be due to that.\n"));
+ head_running = true;
+ }
+ if (!head) {
+ fputs(gettext(problem->explanation), stdout);
+ head = true;
+ }
+ describebriefly(pkg);
+ }
+
+ if (head) putchar('\n');
+ }
+
+ pkg_array_destroy(&array);
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+struct sectionentry {
+ struct sectionentry *next;
+ const char *name;
+ int count;
+};
+
+static bool
+yettobeunpacked(struct pkginfo *pkg, const char **thissect)
+{
+ if (pkg->want != PKG_WANT_INSTALL)
+ return false;
+
+ switch (pkg->status) {
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_INSTALLED:
+ case PKG_STAT_HALFCONFIGURED:
+ case PKG_STAT_TRIGGERSPENDING:
+ case PKG_STAT_TRIGGERSAWAITED:
+ return false;
+ case PKG_STAT_NOTINSTALLED:
+ case PKG_STAT_HALFINSTALLED:
+ case PKG_STAT_CONFIGFILES:
+ if (thissect)
+ *thissect = str_is_set(pkg->section) ? pkg->section :
+ C_("section", "<unknown>");
+ return true;
+ default:
+ internerr("unknown package status '%d'", pkg->status);
+ }
+ return false;
+}
+
+int
+unpackchk(const char *const *argv)
+{
+ int totalcount, sects;
+ struct sectionentry *sectionentries, *se, **sep;
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+ const char *thissect;
+ char buf[20];
+ int width;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ modstatdb_open(msdbrw_readonly);
+
+ totalcount= 0;
+ sectionentries = NULL;
+ sects= 0;
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (!yettobeunpacked(pkg, &thissect)) continue;
+ for (se= sectionentries; se && strcasecmp(thissect,se->name); se= se->next);
+ if (!se) {
+ se = nfmalloc(sizeof(*se));
+ for (sep= &sectionentries;
+ *sep && strcasecmp(thissect,(*sep)->name) > 0;
+ sep= &(*sep)->next);
+ se->name= thissect;
+ se->count= 0;
+ se->next= *sep;
+ *sep= se;
+ sects++;
+ }
+ se->count++; totalcount++;
+ }
+ pkg_hash_iter_free(iter);
+
+ if (totalcount == 0)
+ return 0;
+
+ if (totalcount <= 12) {
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (!yettobeunpacked(pkg, NULL))
+ continue;
+ describebriefly(pkg);
+ }
+ pkg_hash_iter_free(iter);
+ } else if (sects <= 12) {
+ for (se= sectionentries; se; se= se->next) {
+ sprintf(buf,"%d",se->count);
+ printf(_(" %d in %s: "),se->count,se->name);
+ width= 70-strlen(se->name)-strlen(buf);
+ while (width > 59) { putchar(' '); width--; }
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ const char *pkgname;
+
+ if (!yettobeunpacked(pkg,&thissect)) continue;
+ if (strcasecmp(thissect,se->name)) continue;
+ pkgname = pkg_name(pkg, pnaw_nonambig);
+ width -= strlen(pkgname);
+ width--;
+ if (width < 4) { printf(" ..."); break; }
+ printf(" %s", pkgname);
+ }
+ pkg_hash_iter_free(iter);
+ putchar('\n');
+ }
+ } else {
+ printf(P_(" %d package, from the following section:",
+ " %d packages, from the following sections:", totalcount),
+ totalcount);
+ width= 0;
+ for (se= sectionentries; se; se= se->next) {
+ sprintf(buf,"%d",se->count);
+ width -= (6 + strlen(se->name) + strlen(buf));
+ if (width < 0) { putchar('\n'); width= 73 - strlen(se->name) - strlen(buf); }
+ printf(" %s (%d)",se->name,se->count);
+ }
+ putchar('\n');
+ }
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static const struct assert_feature {
+ const char *name;
+ const char *desc;
+ const char *version;
+} assert_features[] = {
+ {
+ .name = "support-predepends",
+ .desc = N_("the Pre-Depends field"),
+ .version = "1.1.0",
+ }, {
+ .name = "working-epoch",
+ .desc = N_("epochs in versions"),
+ .version = "1.4.0.7",
+ }, {
+ .name = "long-filenames",
+ .desc = N_("long filenames in .deb archives"),
+ .version = "1.4.1.17",
+ }, {
+ .name = "multi-conrep",
+ .desc = N_("multiple Conflicts and Replaces"),
+ .version = "1.4.1.19",
+ }, {
+ .name = "multi-arch",
+ .desc = N_("multi-arch fields and semantics"),
+ .version = "1.16.2",
+ }, {
+ .name = "versioned-provides",
+ .desc = N_("versioned relationships in the Provides field"),
+ .version = "1.17.11",
+ }, {
+ .name = "protected-field",
+ .desc = N_("the Protected field"),
+ .version = "1.20.1",
+ }, {
+ .name = NULL,
+ }
+};
+
+static int
+assert_version_support(const char *const *argv,
+ const struct assert_feature *feature)
+{
+ const char *running_version_str;
+ struct dpkg_version running_version = DPKG_VERSION_INIT;
+ struct dpkg_version version = { 0, feature->version, NULL };
+ struct dpkg_error err = DPKG_ERROR_INIT;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ /*
+ * When using the feature asserts, we want to know whether the currently
+ * running dpkg, which we might be running under (say from within a
+ * maintainer script) and which might have a different version, supports
+ * the requested feature. As dpkg is an Essential package, it is expected
+ * to work even when just unpacked, and so its own version is enough.
+ */
+ running_version_str = getenv("DPKG_RUNNING_VERSION");
+
+ /*
+ * If we are not running from within a maintainer script, then that means
+ * once we do, the executed dpkg will support the requested feature, if
+ * we know about it. Always return success in that case.
+ */
+ if (str_is_unset(running_version_str))
+ return 0;
+
+ if (parseversion(&running_version, running_version_str, &err) < 0)
+ ohshit(_("cannot parse dpkg running version '%s': %s"),
+ running_version_str, err.str);
+
+ if (dpkg_version_relate(&running_version, DPKG_RELATION_GE, &version))
+ return 0;
+
+ printf(_("Running version of dpkg does not support %s.\n"
+ " Please upgrade to at least dpkg %s, and then try again.\n"),
+ feature->desc, versiondescribe(&version, vdew_nonambig));
+ return 1;
+}
+
+const char *assert_feature_name;
+
+int
+assert_feature(const char *const *argv)
+{
+ const struct assert_feature *feature;
+
+ if (strcmp(assert_feature_name, "help") == 0) {
+ printf(_("%s assert options - assert whether features are supported:\n"),
+ dpkg_get_progname());
+
+ for (feature = assert_features; feature->name; feature++) {
+ printf(" %-19s %-9s %s\n", feature->name, feature->version,
+ gettext(feature->desc));
+ }
+
+ exit(0);
+ }
+
+ for (feature = assert_features; feature->name; feature++) {
+ if (strcmp(feature->name, assert_feature_name) != 0)
+ continue;
+
+ return assert_version_support(argv, feature);
+ }
+
+ badusage(_("unknown --%s-<feature>"), cipaction->olong);
+}
+
+/**
+ * Print a single package which:
+ * (a) is the target of one or more relevant predependencies.
+ * (b) has itself no unsatisfied pre-dependencies.
+ *
+ * If such a package is present output is the Packages file entry,
+ * which can be massaged as appropriate.
+ *
+ * Exit status:
+ * 0 = a package printed, OK
+ * 1 = no suitable package available
+ * 2 = error
+ */
+int
+predeppackage(const char *const *argv)
+{
+ static struct varbuf vb;
+
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg = NULL, *startpkg, *trypkg;
+ struct dependency *dep;
+ struct deppossi *possi, *provider;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
+ /* We use clientdata->istobe to detect loops. */
+ clear_istobes();
+
+ dep = NULL;
+ iter = pkg_hash_iter_new();
+ while (!dep && (pkg = pkg_hash_iter_next_pkg(iter))) {
+ /* Ignore packages user doesn't want. */
+ if (pkg->want != PKG_WANT_INSTALL)
+ continue;
+ /* Ignore packages not available. */
+ if (!pkg->archives)
+ continue;
+ pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
+ for (dep= pkg->available.depends; dep; dep= dep->next) {
+ if (dep->type != dep_predepends) continue;
+ if (depisok(dep, &vb, NULL, NULL, true))
+ continue;
+ /* This will leave dep non-NULL, and so exit the loop. */
+ break;
+ }
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ /* If dep is NULL we go and get the next package. */
+ }
+ pkg_hash_iter_free(iter);
+
+ if (!dep)
+ return 1; /* Not found. */
+ if (pkg == NULL)
+ internerr("unexpected unfound package");
+
+ startpkg= pkg;
+ pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
+
+ /* OK, we have found an unsatisfied predependency.
+ * Now go and find the first thing we need to install, as a first step
+ * towards satisfying it. */
+ do {
+ /* We search for a package which would satisfy dep, and put it in pkg. */
+ for (possi = dep->list, pkg = NULL;
+ !pkg && possi;
+ possi=possi->next) {
+ struct deppossi_pkg_iterator *possi_iter;
+
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_available);
+ while (!pkg && (trypkg = deppossi_pkg_iter_next(possi_iter))) {
+ if (trypkg->archives &&
+ trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL &&
+ versionsatisfied(&trypkg->available, possi)) {
+ pkg = trypkg;
+ break;
+ }
+ for (provider = possi->ed->depended.available;
+ !pkg && provider;
+ provider = provider->next) {
+ if (provider->up->type != dep_provides)
+ continue;
+ if (!pkg_virtual_deppossi_satisfied(possi, provider))
+ continue;
+ trypkg = provider->up->up;
+ if (!trypkg->archives)
+ continue;
+ if (trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL) {
+ pkg = trypkg;
+ break;
+ }
+ }
+ }
+ deppossi_pkg_iter_free(possi_iter);
+ }
+ if (!pkg) {
+ varbuf_reset(&vb);
+ describedepcon(&vb,dep);
+ varbuf_end_str(&vb);
+ notice(_("cannot see how to satisfy pre-dependency:\n %s"), vb.buf);
+ ohshit(_("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)"),
+ pkgbin_name(dep->up, &dep->up->available, pnaw_nonambig),
+ pkgbin_name(startpkg, &startpkg->available, pnaw_nonambig));
+ }
+ pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL;
+ for (dep= pkg->available.depends; dep; dep= dep->next) {
+ if (dep->type != dep_predepends) continue;
+ if (depisok(dep, &vb, NULL, NULL, true))
+ continue;
+ /* This will leave dep non-NULL, and so exit the loop. */
+ break;
+ }
+ } while (dep);
+
+ /* OK, we've found it - pkg has no unsatisfied pre-dependencies! */
+ write_stanza(stdout, _("<standard output>"), pkg, &pkg->available);
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+int
+printarch(const char *const *argv)
+{
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ printf("%s\n", dpkg_arch_get(DPKG_ARCH_NATIVE)->name);
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+int
+print_foreign_arches(const char *const *argv)
+{
+ struct dpkg_arch *arch;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ dpkg_arch_load_list();
+
+ for (arch = dpkg_arch_get_list(); arch; arch = arch->next) {
+ if (arch->type != DPKG_ARCH_FOREIGN)
+ continue;
+
+ printf("%s\n", arch->name);
+ }
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+int
+validate_pkgname(const char *const *argv)
+{
+ const char *emsg;
+
+ if (!argv[0] || argv[1])
+ badusage(_("--%s takes one <pkgname> argument"), cipaction->olong);
+
+ emsg = pkg_name_is_illegal(argv[0]);
+ if (emsg)
+ ohshit(_("package name '%s' is invalid: %s"), argv[0], emsg);
+
+ return 0;
+}
+
+int
+validate_trigname(const char *const *argv)
+{
+ const char *emsg;
+
+ if (!argv[0] || argv[1])
+ badusage(_("--%s takes one <trigname> argument"), cipaction->olong);
+
+ emsg = trig_name_is_illegal(argv[0]);
+ if (emsg)
+ ohshit(_("trigger name '%s' is invalid: %s"), argv[0], emsg);
+
+ return 0;
+}
+
+int
+validate_archname(const char *const *argv)
+{
+ const char *emsg;
+
+ if (!argv[0] || argv[1])
+ badusage(_("--%s takes one <archname> argument"), cipaction->olong);
+
+ emsg = dpkg_arch_name_is_illegal(argv[0]);
+ if (emsg)
+ ohshit(_("architecture name '%s' is invalid: %s"), argv[0], emsg);
+
+ return 0;
+}
+
+int
+validate_version(const char *const *argv)
+{
+ struct dpkg_version version;
+ struct dpkg_error err;
+
+ if (!argv[0] || argv[1])
+ badusage(_("--%s takes one <version> argument"), cipaction->olong);
+
+ if (parseversion(&version, argv[0], &err) < 0) {
+ dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[0]);
+ dpkg_error_destroy(&err);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+cmpversions(const char *const *argv)
+{
+ struct relationinfo {
+ const char *op;
+ /* These values are exit status codes. */
+ int if_lesser, if_equal, if_greater;
+ int if_none_a, if_none_both, if_none_b;
+ bool obsolete;
+ };
+
+ static const struct relationinfo relationinfos[]= {
+ {
+ .op = "le",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "lt",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "eq",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "ne",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = "ge",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = "gt",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_SUCCESS,
+ },
+
+ /* These treat an empty version as later than any version. */
+ {
+ .op = "le-nl",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = "lt-nl",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = "ge-nl",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "gt-nl",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_FAILURE,
+ },
+
+ /* For compatibility with dpkg control file syntax. */
+ {
+ .op = "<",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ .obsolete = true,
+ }, {
+ .op = "<=",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "<<",
+ .if_lesser = EXIT_SUCCESS,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_SUCCESS,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = "=",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_FAILURE,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_FAILURE,
+ }, {
+ .op = ">",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_SUCCESS,
+ .obsolete = true,
+ }, {
+ .op = ">=",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_SUCCESS,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_SUCCESS,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = ">>",
+ .if_lesser = EXIT_FAILURE,
+ .if_equal = EXIT_FAILURE,
+ .if_greater = EXIT_SUCCESS,
+ .if_none_a = EXIT_FAILURE,
+ .if_none_both = EXIT_FAILURE,
+ .if_none_b = EXIT_SUCCESS,
+ }, {
+ .op = NULL,
+ }
+ };
+
+ const struct relationinfo *rip;
+ struct dpkg_version a, b;
+ struct dpkg_error err;
+ int rc;
+
+ if (!argv[0] || !argv[1] || !argv[2] || argv[3])
+ badusage(_("--compare-versions takes three arguments:"
+ " <version> <relation> <version>"));
+
+ for (rip = relationinfos; rip->op && strcmp(rip->op, argv[1]); rip++)
+ ;
+
+ if (!rip->op)
+ badusage(_("--compare-versions bad relation"));
+
+ if (rip->obsolete)
+ warning(_("--%s used with obsolete relation operator '%s'"),
+ cipaction->olong, rip->op);
+
+ if (*argv[0] && strcmp(argv[0],"<unknown>")) {
+ if (parseversion(&a, argv[0], &err) < 0) {
+ dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[0]);
+ dpkg_error_destroy(&err);
+ }
+ } else {
+ dpkg_version_blank(&a);
+ }
+ if (*argv[2] && strcmp(argv[2],"<unknown>")) {
+ if (parseversion(&b, argv[2], &err) < 0) {
+ dpkg_error_print(&err, _("version '%s' has bad syntax"), argv[2]);
+ dpkg_error_destroy(&err);
+ }
+ } else {
+ dpkg_version_blank(&b);
+ }
+ if (!dpkg_version_is_informative(&a)) {
+ if (dpkg_version_is_informative(&b))
+ return rip->if_none_a;
+ else
+ return rip->if_none_both;
+ } else if (!dpkg_version_is_informative(&b)) {
+ return rip->if_none_b;
+ }
+ rc = dpkg_version_compare(&a, &b);
+ debug(dbg_general, "cmpversions a='%s' b='%s' r=%d",
+ versiondescribe_c(&a,vdew_always),
+ versiondescribe_c(&b,vdew_always),
+ rc);
+ if (rc > 0)
+ return rip->if_greater;
+ else if (rc < 0)
+ return rip->if_lesser;
+ else
+ return rip->if_equal;
+}
diff --git a/src/main/errors.c b/src/main/errors.c
new file mode 100644
index 0000000..50d4155
--- /dev/null
+++ b/src/main/errors.c
@@ -0,0 +1,137 @@
+/*
+ * dpkg - main program for package management
+ * errors.c - per package error handling
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-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 <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/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/options.h>
+
+#include "main.h"
+
+bool abort_processing = false;
+
+static int nerrs = 0;
+
+struct error_report {
+ struct error_report *next;
+ char *what;
+};
+
+static struct error_report *reports = NULL;
+static struct error_report **lastreport= &reports;
+static struct error_report emergency;
+
+static void
+enqueue_error_report(const char *arg)
+{
+ struct error_report *nr;
+
+ nr = malloc(sizeof(*nr));
+ if (!nr) {
+ notice(_("failed to allocate memory for new entry in list of failed packages: %s"),
+ strerror(errno));
+ abort_processing = true;
+ nr= &emergency;
+ }
+ nr->what = m_strdup(arg);
+ nr->next = NULL;
+ *lastreport= nr;
+ lastreport= &nr->next;
+
+ if (++nerrs < errabort)
+ return;
+ notice(_("too many errors, stopping"));
+ abort_processing = true;
+}
+
+void
+print_error_perpackage(const char *emsg, const void *data)
+{
+ const char *pkgname = data;
+
+ notice(_("error processing package %s (--%s):\n %s"),
+ pkgname, cipaction->olong, emsg);
+
+ statusfd_send("status: %s : %s : %s", pkgname, "error", emsg);
+
+ enqueue_error_report(pkgname);
+}
+
+void
+print_error_perarchive(const char *emsg, const void *data)
+{
+ const char *filename = data;
+
+ notice(_("error processing archive %s (--%s):\n %s"),
+ filename, cipaction->olong, emsg);
+
+ statusfd_send("status: %s : %s : %s", filename, "error", emsg);
+
+ enqueue_error_report(filename);
+}
+
+int
+reportbroken_retexitstatus(int ret)
+{
+ if (reports) {
+ fputs(_("Errors were encountered while processing:\n"),stderr);
+ while (reports) {
+ fprintf(stderr," %s\n",reports->what);
+ free(reports->what);
+ reports= reports->next;
+ }
+ }
+ if (abort_processing) {
+ fputs(_("Processing was halted because there were too many errors.\n"),stderr);
+ }
+ return nerrs ? 1 : ret;
+}
+
+bool
+skip_due_to_hold(struct pkginfo *pkg)
+{
+ if (pkg->want != PKG_WANT_HOLD)
+ return false;
+ if (in_force(FORCE_HOLD)) {
+ notice(_("package %s was on hold, processing it anyway as you requested"),
+ pkg_name(pkg, pnaw_nonambig));
+ return false;
+ }
+ printf(_("Package %s is on hold, not touching it. Use --force-hold to override.\n"),
+ pkg_name(pkg, pnaw_nonambig));
+ return true;
+}
+
diff --git a/src/main/file-match.c b/src/main/file-match.c
new file mode 100644
index 0000000..51bdb0d
--- /dev/null
+++ b/src/main/file-match.c
@@ -0,0 +1,49 @@
+/*
+ * dpkg - main program for package management
+ * file-match.c - file name/type match tracking functions
+ *
+ * Copyright © 2011 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 <stdlib.h>
+
+#include <dpkg/dpkg.h>
+
+#include "file-match.h"
+
+struct match_node *
+match_node_new(const char *name, const char *type, struct match_node *next)
+{
+ struct match_node *node;
+
+ node = m_malloc(sizeof(*node));
+ node->next = next;
+ node->filename = m_strdup(name);
+ node->filetype = m_strdup(type);
+
+ return node;
+}
+
+void
+match_node_free(struct match_node *node)
+{
+ free(node->filetype);
+ free(node->filename);
+ free(node);
+}
diff --git a/src/main/file-match.h b/src/main/file-match.h
new file mode 100644
index 0000000..db7a40b
--- /dev/null
+++ b/src/main/file-match.h
@@ -0,0 +1,35 @@
+/*
+ * dpkg - main program for package management
+ * file-match.h - file name/type match tracking functions
+ *
+ * Copyright © 2011 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 DPKG_FILE_MATCH_H
+#define DPKG_FILE_MATCH_H
+
+struct match_node {
+ struct match_node *next;
+ char *filetype;
+ char *filename;
+};
+
+struct match_node *
+match_node_new(const char *name, const char *type, struct match_node *next);
+void
+match_node_free(struct match_node *node);
+
+#endif /* DPKG_FILE_MATCH_H */
diff --git a/src/main/filters.c b/src/main/filters.c
new file mode 100644
index 0000000..f770fb7
--- /dev/null
+++ b/src/main/filters.c
@@ -0,0 +1,133 @@
+/*
+ * dpkg - main program for package management
+ * filters.c - filtering routines for excluding bits of packages
+ *
+ * Copyright © 2007, 2008 Tollef Fog Heen <tfheen@err.no>
+ * Copyright © 2008, 2010, 2012-2014 Guillem Jover <guillem@debian.org>
+ * Copyright © 2010 Canonical Ltd.
+ * written by Martin Pitt <martin.pitt@canonical.com>
+ *
+ * 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 <fnmatch.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+#include "filters.h"
+
+struct filter_node {
+ struct filter_node *next;
+ char *pattern;
+ bool include;
+};
+
+static struct filter_node *filter_head = NULL;
+static struct filter_node **filter_tail = &filter_head;
+
+void
+filter_add(const char *pattern, bool include)
+{
+ struct filter_node *filter;
+
+ debug(dbg_general, "adding %s filter for '%s'",
+ include ? "include" : "exclude", pattern);
+
+ filter = m_malloc(sizeof(*filter));
+ filter->pattern = m_strdup(pattern);
+ filter->include = include;
+ filter->next = NULL;
+
+ *filter_tail = filter;
+ filter_tail = &filter->next;
+}
+
+bool
+filter_should_skip(struct tar_entry *ti)
+{
+ struct filter_node *f;
+ bool skip = false;
+
+ if (!filter_head)
+ return false;
+
+ /* Last match wins. */
+ for (f = filter_head; f != NULL; f = f->next) {
+ debug(dbg_eachfile, "filter comparing '%s' and '%s'",
+ &ti->name[1], f->pattern);
+
+ if (fnmatch(f->pattern, &ti->name[1], 0) == 0) {
+ if (f->include) {
+ skip = false;
+ debug(dbg_eachfile, "filter including %s",
+ ti->name);
+ } else {
+ skip = true;
+ debug(dbg_eachfile, "filter removing %s",
+ ti->name);
+ }
+ }
+ }
+
+ /* We need to keep directories (or symlinks to directories) if a
+ * glob excludes them, but a more specific include glob brings back
+ * files; XXX the current implementation will probably include more
+ * directories than necessary, but better err on the side of caution
+ * than failing with “no such file or directory” (which would leave
+ * the package in a very bad state). */
+ if (skip && (ti->type == TAR_FILETYPE_DIR ||
+ ti->type == TAR_FILETYPE_SYMLINK)) {
+ debug(dbg_eachfile,
+ "filter seeing if '%s' needs to be reincluded",
+ &ti->name[1]);
+
+ for (f = filter_head; f != NULL; f = f->next) {
+ const char *wildcard;
+ int path_len;
+
+ if (!f->include)
+ continue;
+
+ /* Calculate the offset of the first wildcard
+ * character in the pattern. */
+ wildcard = strpbrk(f->pattern, "*?[\\");
+ if (wildcard)
+ path_len = wildcard - f->pattern;
+ else
+ path_len = strlen(f->pattern);
+
+ /* Ignore any trailing slash for the comparison. */
+ while (path_len && f->pattern[path_len - 1] == '/')
+ path_len--;
+
+ debug(dbg_eachfiledetail,
+ "filter subpattern '%.*s'", path_len, f->pattern);
+
+ if (strncmp(&ti->name[1], f->pattern, path_len) == 0) {
+ debug(dbg_eachfile, "filter reincluding %s",
+ ti->name);
+ return false;
+ }
+ }
+ }
+
+ return skip;
+}
diff --git a/src/main/filters.h b/src/main/filters.h
new file mode 100644
index 0000000..b878e7e
--- /dev/null
+++ b/src/main/filters.h
@@ -0,0 +1,37 @@
+/*
+ * dpkg - main program for package management
+ * filters.h - external definitions for filter handling
+ *
+ * Copyright © 2007, 2008 Tollef Fog Heen <tfheen@err.no>
+ * Copyright © 2008, 2010 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 DPKG_FILTERS_H
+#define DPKG_FILTERS_H
+
+#include <stdbool.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/tarfn.h>
+
+DPKG_BEGIN_DECLS
+
+void filter_add(const char *glob, bool include);
+bool filter_should_skip(struct tar_entry *ti);
+
+DPKG_END_DECLS
+
+#endif
diff --git a/src/main/help.c b/src/main/help.c
new file mode 100644
index 0000000..c869aac
--- /dev/null
+++ b/src/main/help.c
@@ -0,0 +1,359 @@
+/*
+ * dpkg - main program for package management
+ * help.c - various helper routines
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/path.h>
+#include <dpkg/file.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+const char *const statusstrings[]= {
+ [PKG_STAT_NOTINSTALLED] = N_("not installed"),
+ [PKG_STAT_CONFIGFILES] = N_("not installed but configs remain"),
+ [PKG_STAT_HALFINSTALLED] = N_("broken due to failed removal or installation"),
+ [PKG_STAT_UNPACKED] = N_("unpacked but not configured"),
+ [PKG_STAT_HALFCONFIGURED] = N_("broken due to postinst failure"),
+ [PKG_STAT_TRIGGERSAWAITED] = N_("awaiting trigger processing by another package"),
+ [PKG_STAT_TRIGGERSPENDING] = N_("triggered"),
+ [PKG_STAT_INSTALLED] = N_("installed")
+};
+
+struct fsys_namenode *
+namenodetouse(struct fsys_namenode *namenode, struct pkginfo *pkg,
+ struct pkgbin *pkgbin)
+{
+ struct fsys_namenode *fnn;
+
+ if (!namenode->divert)
+ return namenode;
+
+ debug(dbg_eachfile, "namenodetouse namenode='%s' pkg=%s",
+ namenode->name, pkgbin_name(pkg, pkgbin, pnaw_always));
+
+ fnn = (namenode->divert->useinstead && namenode->divert->pkgset != pkg->set)
+ ? namenode->divert->useinstead : namenode;
+
+ debug(dbg_eachfile,
+ "namenodetouse ... useinstead=%s camefrom=%s pkg=%s return %s",
+ namenode->divert->useinstead ? namenode->divert->useinstead->name : "<none>",
+ namenode->divert->camefrom ? namenode->divert->camefrom->name : "<none>",
+ namenode->divert->pkgset ? namenode->divert->pkgset->name : "<none>",
+ fnn->name);
+
+ return fnn;
+}
+
+bool
+find_command(const char *prog)
+{
+ struct varbuf filename = VARBUF_INIT;
+ const char *path_list;
+ const char *path, *path_end;
+ size_t path_len;
+
+ if (prog[0] == '/')
+ return file_is_exec(prog);
+
+ path_list = getenv("PATH");
+ if (!path_list)
+ ohshit(_("PATH is not set"));
+
+ for (path = path_list; path; path = *path_end ? path_end + 1 : NULL) {
+ path_end = strchrnul(path, ':');
+ path_len = (size_t)(path_end - path);
+
+ varbuf_reset(&filename);
+ varbuf_add_buf(&filename, path, path_len);
+ if (path_len)
+ varbuf_add_char(&filename, '/');
+ varbuf_add_str(&filename, prog);
+ varbuf_end_str(&filename);
+
+ if (file_is_exec(filename.buf)) {
+ varbuf_destroy(&filename);
+ return true;
+ }
+ }
+
+ varbuf_destroy(&filename);
+ return false;
+}
+
+/**
+ * Verify that some programs can be found in the PATH.
+ */
+void checkpath(void) {
+ static const char *const prog_list[] = {
+ DEFAULTSHELL,
+ RM,
+ TAR,
+ DIFF,
+ BACKEND,
+ /* Mac OS X uses dyld (Mach-O) instead of ld.so (ELF), and does not have
+ * an ldconfig. */
+#if defined(__APPLE__) && defined(__MACH__)
+ "update_dyld_shared_cache",
+#elif defined(__GLIBC__) || defined(__UCLIBC__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+ "ldconfig",
+#endif
+#if BUILD_START_STOP_DAEMON
+ "start-stop-daemon",
+#endif
+ NULL
+ };
+
+ const char *const *prog;
+ int warned= 0;
+
+ for (prog = prog_list; *prog; prog++) {
+ if (!find_command(*prog)) {
+ warning(_("'%s' not found in PATH or not executable"), *prog);
+ warned++;
+ }
+ }
+
+ if (warned)
+ forcibleerr(FORCE_BAD_PATH,
+ P_("%d expected program not found in PATH or not executable\n%s",
+ "%d expected programs not found in PATH or not executable\n%s",
+ warned),
+ warned, _("Note: root's PATH should usually contain "
+ "/usr/local/sbin, /usr/sbin and /sbin"));
+}
+
+bool
+ignore_depends(const struct pkginfo *pkg)
+{
+ struct pkg_list *id;
+ for (id= ignoredependss; id; id= id->next)
+ if (id->pkg == pkg)
+ return true;
+ return false;
+}
+
+static bool
+ignore_depends_possi(struct deppossi *possi)
+{
+ struct deppossi_pkg_iterator *possi_iter;
+ struct pkginfo *pkg;
+
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_installed);
+ while ((pkg = deppossi_pkg_iter_next(possi_iter))) {
+ if (ignore_depends(pkg)) {
+ deppossi_pkg_iter_free(possi_iter);
+ return true;
+ }
+ }
+ deppossi_pkg_iter_free(possi_iter);
+
+ return false;
+}
+
+bool
+force_depends(struct deppossi *possi)
+{
+ return in_force(FORCE_DEPENDS) ||
+ ignore_depends_possi(possi) ||
+ ignore_depends(possi->up->up);
+}
+
+bool
+force_breaks(struct deppossi *possi)
+{
+ return in_force(FORCE_BREAKS) ||
+ ignore_depends_possi(possi) ||
+ ignore_depends(possi->up->up);
+}
+
+bool
+force_conflicts(struct deppossi *possi)
+{
+ return in_force(FORCE_CONFLICTS);
+}
+
+void clear_istobes(void) {
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter)) != NULL) {
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ pkg->clientdata->replacingfilesandsaid= 0;
+ }
+ pkg_hash_iter_free(iter);
+}
+
+/*
+ * Returns true if the directory contains conffiles belonging to pkg,
+ * false otherwise.
+ */
+bool
+dir_has_conffiles(struct fsys_namenode *file, struct pkginfo *pkg)
+{
+ struct conffile *conff;
+ size_t namelen;
+
+ debug(dbg_veryverbose, "dir_has_conffiles '%s' (from %s)", file->name,
+ pkg_name(pkg, pnaw_always));
+ namelen = strlen(file->name);
+ for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
+ if (conff->obsolete || conff->remove_on_upgrade)
+ continue;
+ if (strncmp(file->name, conff->name, namelen) == 0 &&
+ strlen(conff->name) > namelen && conff->name[namelen] == '/') {
+ debug(dbg_veryverbose, "directory %s has conffile %s from %s",
+ file->name, conff->name, pkg_name(pkg, pnaw_always));
+ return true;
+ }
+ }
+ debug(dbg_veryverbose, "dir_has_conffiles no");
+ return false;
+}
+
+/*
+ * Returns true if the file is used by packages other than pkg,
+ * false otherwise.
+ */
+bool
+dir_is_used_by_others(struct fsys_namenode *file, struct pkginfo *pkg)
+{
+ struct fsys_node_pkgs_iter *iter;
+ struct pkginfo *other_pkg;
+
+ debug(dbg_veryverbose, "dir_is_used_by_others '%s' (except %s)", file->name,
+ pkg ? pkg_name(pkg, pnaw_always) : "<none>");
+
+ iter = fsys_node_pkgs_iter_new(file);
+ while ((other_pkg = fsys_node_pkgs_iter_next(iter))) {
+ debug(dbg_veryverbose, "dir_is_used_by_others considering %s ...",
+ pkg_name(other_pkg, pnaw_always));
+ if (other_pkg == pkg)
+ continue;
+
+ fsys_node_pkgs_iter_free(iter);
+ debug(dbg_veryverbose, "dir_is_used_by_others yes");
+ return true;
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ debug(dbg_veryverbose, "dir_is_used_by_others no");
+ return false;
+}
+
+/*
+ * Returns true if the file is used by pkg, false otherwise.
+ */
+bool
+dir_is_used_by_pkg(struct fsys_namenode *file, struct pkginfo *pkg,
+ struct fsys_namenode_list *list)
+{
+ struct fsys_namenode_list *node;
+ size_t namelen;
+
+ debug(dbg_veryverbose, "dir_is_used_by_pkg '%s' (by %s)",
+ file->name, pkg ? pkg_name(pkg, pnaw_always) : "<none>");
+
+ namelen = strlen(file->name);
+
+ for (node = list; node; node = node->next) {
+ debug(dbg_veryverbose, "dir_is_used_by_pkg considering %s ...",
+ node->namenode->name);
+
+ if (strncmp(file->name, node->namenode->name, namelen) == 0 &&
+ strlen(node->namenode->name) > namelen &&
+ node->namenode->name[namelen] == '/') {
+ debug(dbg_veryverbose, "dir_is_used_by_pkg yes");
+ return true;
+ }
+ }
+
+ debug(dbg_veryverbose, "dir_is_used_by_pkg no");
+
+ return false;
+}
+
+/**
+ * Mark a conffile as obsolete.
+ *
+ * @param pkg The package owning the conffile.
+ * @param namenode The namenode for the obsolete conffile.
+ */
+void
+conffile_mark_obsolete(struct pkginfo *pkg, struct fsys_namenode *namenode)
+{
+ struct conffile *conff;
+
+ for (conff = pkg->installed.conffiles; conff; conff = conff->next) {
+ if (strcmp(conff->name, namenode->name) == 0) {
+ debug(dbg_conff, "marking %s conffile %s as obsolete",
+ pkg_name(pkg, pnaw_always), conff->name);
+ conff->obsolete = true;
+ return;
+ }
+ }
+}
+
+/**
+ * Mark all package conffiles as old.
+ *
+ * @param pkg The package owning the conffiles.
+ */
+void
+pkg_conffiles_mark_old(struct pkginfo *pkg)
+{
+ const struct conffile *conff;
+ struct fsys_namenode *namenode;
+
+ for (conff = pkg->installed.conffiles; conff; conff = conff->next) {
+ namenode = fsys_hash_find_node(conff->name, 0); /* XXX */
+ namenode->flags |= FNNF_OLD_CONFF;
+ if (!namenode->oldhash)
+ namenode->oldhash = conff->hash;
+ debug(dbg_conffdetail, "%s '%s' namenode '%s' flags %o", __func__,
+ conff->name, namenode->name, namenode->flags);
+ }
+}
+
+void
+log_action(const char *action, struct pkginfo *pkg, struct pkgbin *pkgbin)
+{
+ log_message("%s %s %s %s", action, pkgbin_name(pkg, pkgbin, pnaw_always),
+ versiondescribe_c(&pkg->installed.version, vdew_nonambig),
+ versiondescribe_c(&pkg->available.version, vdew_nonambig));
+ statusfd_send("processing: %s: %s", action,
+ pkgbin_name(pkg, pkgbin, pnaw_nonambig));
+}
diff --git a/src/main/main.c b/src/main/main.c
new file mode 100644
index 0000000..6f0633e
--- /dev/null
+++ b/src/main/main.c
@@ -0,0 +1,779 @@
+/*
+ * dpkg - main program for package management
+ * main.c - main program
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2016 Guillem Jover <guillem@debian.org>
+ * Copyright © 2010 Canonical Ltd.
+ * written by Martin Pitt <martin.pitt@canonical.com>
+ *
+ * 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>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/c-ctype.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/pager.h>
+#include <dpkg/options.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+#include "filters.h"
+
+static int
+printversion(const char *const *argv)
+{
+ if (f_robot) {
+ printf("%s", PACKAGE_VERSION);
+ } else {
+ printf(_("Debian '%s' package management program version %s.\n"),
+ DPKG, PACKAGE_RELEASE);
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+ }
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+/*
+ * FIXME: Options that need fixing:
+ * dpkg --command-fd
+ */
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option>...] <command>\n"
+"\n"), DPKG);
+
+ printf(_(
+"Commands:\n"
+" -i|--install <.deb file name>... | -R|--recursive <directory>...\n"
+" --unpack <.deb file name>... | -R|--recursive <directory>...\n"
+" -A|--record-avail <.deb file name>... | -R|--recursive <directory>...\n"
+" --configure <package>... | -a|--pending\n"
+" --triggers-only <package>... | -a|--pending\n"
+" -r|--remove <package>... | -a|--pending\n"
+" -P|--purge <package>... | -a|--pending\n"
+" -V|--verify [<package>...] Verify the integrity of package(s).\n"
+" --get-selections [<pattern>...] Get list of selections to stdout.\n"
+" --set-selections Set package selections from stdin.\n"
+" --clear-selections Deselect every non-essential package.\n"
+" --update-avail [<Packages-file>] Replace available packages info.\n"
+" --merge-avail [<Packages-file>] Merge with info from file.\n"
+" --clear-avail Erase existing available info.\n"
+" --forget-old-unavail Forget uninstalled unavailable pkgs.\n"
+" -s|--status [<package>...] Display package status details.\n"
+" -p|--print-avail [<package>...] Display available version details.\n"
+" -L|--listfiles <package>... List files 'owned' by package(s).\n"
+" -l|--list [<pattern>...] List packages concisely.\n"
+" -S|--search <pattern>... Find package(s) owning file(s).\n"
+" -C|--audit [<package>...] Check for broken package(s).\n"
+" --yet-to-unpack Print packages selected for installation.\n"
+" --predep-package Print pre-dependencies to unpack.\n"
+" --add-architecture <arch> Add <arch> to the list of architectures.\n"
+" --remove-architecture <arch> Remove <arch> from the list of architectures.\n"
+" --print-architecture Print dpkg architecture.\n"
+" --print-foreign-architectures Print allowed foreign architectures.\n"
+" --assert-help Show help on assertions.\n"
+" --assert-<feature> Assert support for the specified feature.\n"
+" --validate-<thing> <string> Validate a <thing>'s <string>.\n"
+" --compare-versions <a> <op> <b> Compare version numbers - see below.\n"
+" --force-help Show help on forcing.\n"
+" -Dh|--debug=help Show help on debugging.\n"
+"\n"));
+
+ printf(_(
+" -?, --help Show this help message.\n"
+" --version Show the version.\n"
+"\n"));
+
+ printf(_(
+"Validatable things: pkgname, archname, trigname, version.\n"
+"\n"));
+
+ printf(_(
+"Use dpkg with -b, --build, -c, --contents, -e, --control, -I, --info,\n"
+" -f, --field, -x, --extract, -X, --vextract, --ctrl-tarfile, --fsys-tarfile\n"
+"on archives (type %s --help).\n"
+"\n"), BACKEND);
+
+ printf(_(
+"Options:\n"
+" --admindir=<directory> Use <directory> instead of %s.\n"
+" --root=<directory> Install on a different root directory.\n"
+" --instdir=<directory> Change installation dir without changing admin dir.\n"
+" --pre-invoke=<command> Set a pre-invoke hook.\n"
+" --post-invoke=<command> Set a post-invoke hook.\n"
+" --path-exclude=<pattern> Do not install paths which match a shell pattern.\n"
+" --path-include=<pattern> Re-include a pattern after a previous exclusion.\n"
+" -O|--selected-only Skip packages not selected for install/upgrade.\n"
+" -E|--skip-same-version Skip packages with same installed version/arch.\n"
+" -G|--refuse-downgrade Skip packages with earlier version than installed.\n"
+" -B|--auto-deconfigure Install even if it would break some other package.\n"
+" --[no-]triggers Skip or force consequential trigger processing.\n"
+" --verify-format=<format> Verify output format (supported: 'rpm').\n"
+" --no-pager Disables the use of any pager.\n"
+" --no-debsig Do not try to verify package signatures.\n"
+" --no-act|--dry-run|--simulate\n"
+" Just say what we would do - don't do it.\n"
+" -D|--debug=<octal> Enable debugging (see -Dhelp or --debug=help).\n"
+" --status-fd <n> Send status change updates to file descriptor <n>.\n"
+" --status-logger=<command> Send status change updates to <command>'s stdin.\n"
+" --log=<filename> Log status changes and actions to <filename>.\n"
+" --ignore-depends=<package>[,...]\n"
+" Ignore dependencies involving <package>.\n"
+" --force-<thing>[,...] Override problems (see --force-help).\n"
+" --no-force-<thing>[,...] Stop when problems encountered.\n"
+" --refuse-<thing>[,...] Ditto.\n"
+" --abort-after <n> Abort after encountering <n> errors.\n"
+" --robot Use machine-readable output on some commands.\n"
+"\n"), ADMINDIR);
+
+ printf(_(
+"Comparison operators for --compare-versions are:\n"
+" lt le eq ne ge gt (treat empty version as earlier than any version);\n"
+" lt-nl le-nl ge-nl gt-nl (treat empty version as later than any version);\n"
+" < << <= = >= >> > (only for compatibility with control file syntax).\n"
+"\n"));
+
+ printf(_(
+"Use 'apt' or 'aptitude' for user-friendly package management.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static const char printforhelp[] = N_(
+"Type dpkg --help for help about installing and deinstalling packages [*];\n"
+"Use 'apt' or 'aptitude' for user-friendly package management;\n"
+"Type dpkg -Dhelp for a list of dpkg debug flag values;\n"
+"Type dpkg --force-help for a list of forcing options;\n"
+"Type dpkg-deb --help for help about manipulating *.deb files;\n"
+"\n"
+"Options marked [*] produce a lot of output - pipe it through 'less' or 'more' !");
+
+int f_robot = 0;
+int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
+int f_autodeconf=0, f_nodebsig=0;
+int f_triggers = 0;
+
+int errabort = 50;
+struct pkg_list *ignoredependss = NULL;
+
+#define DBG_DEF(n, d) \
+ { .flag = dbg_##n, .name = #n, .desc = d }
+
+static const struct debuginfo {
+ int flag;
+ const char *name;
+ const char *desc;
+} debuginfos[] = {
+ DBG_DEF(general, N_("Generally helpful progress information")),
+ DBG_DEF(scripts, N_("Invocation and status of maintainer scripts")),
+ DBG_DEF(eachfile, N_("Output for each file processed")),
+ DBG_DEF(eachfiledetail, N_("Lots of output for each file processed")),
+ DBG_DEF(conff, N_("Output for each configuration file")),
+ DBG_DEF(conffdetail, N_("Lots of output for each configuration file")),
+ DBG_DEF(depcon, N_("Dependencies and conflicts")),
+ DBG_DEF(depcondetail, N_("Lots of dependencies/conflicts output")),
+ DBG_DEF(triggers, N_("Trigger activation and processing")),
+ DBG_DEF(triggersdetail, N_("Lots of output regarding triggers")),
+ DBG_DEF(triggersstupid, N_("Silly amounts of output regarding triggers")),
+ DBG_DEF(veryverbose, N_("Lots of drivel about eg the dpkg/info directory")),
+ DBG_DEF(stupidlyverbose, N_("Insane amounts of drivel")),
+ { 0, NULL, NULL }
+};
+
+static void
+set_debug(const struct cmdinfo *cpi, const char *value)
+{
+ long mask;
+ const struct debuginfo *dip;
+
+ if (*value == 'h') {
+ printf(_(
+"%s debugging option, --debug=<octal> or -D<octal>:\n"
+"\n"
+" Number Ref. in source Description\n"), DPKG);
+
+ for (dip = debuginfos; dip->name; dip++)
+ printf(" %6o %-16s %s\n", dip->flag, dip->name, gettext(dip->desc));
+
+ printf(_("\n"
+"Debugging options can be mixed using bitwise-or.\n"
+"Note that the meanings and values are subject to change.\n"));
+ m_output(stdout, _("<standard output>"));
+ exit(0);
+ }
+
+ mask = debug_parse_mask(value);
+ if (mask < 0)
+ badusage(_("--%s requires a positive octal argument"), cpi->olong);
+}
+
+static void
+set_no_pager(const struct cmdinfo *ci, const char *value)
+{
+ pager_enable(false);
+
+ /* Let's communicate this to our backends. */
+ setenv("DPKG_PAGER", "cat", 1);
+}
+
+static void
+set_filter(const struct cmdinfo *cip, const char *value)
+{
+ filter_add(value, cip->arg_int);
+}
+
+static void
+set_verify_format(const struct cmdinfo *cip, const char *value)
+{
+ if (!verify_set_output(value))
+ badusage(_("unknown verify output format '%s'"), value);
+}
+
+static void
+set_ignore_depends(const struct cmdinfo *cip, const char *value)
+{
+ char *copy, *p;
+
+ copy= m_malloc(strlen(value)+2);
+ strcpy(copy,value);
+ copy[strlen(value) + 1] = '\0';
+ for (p=copy; *p; p++) {
+ if (*p != ',') continue;
+ *p++ = '\0';
+ if (!*p || *p==',' || p==copy+1)
+ badusage(_("null package name in --%s comma-separated list '%.250s'"),
+ cip->olong, value);
+ }
+ p= copy;
+ while (*p) {
+ struct pkginfo *pkg;
+
+ pkg = dpkg_options_parse_pkgname(cip, p);
+ pkg_list_prepend(&ignoredependss, pkg);
+
+ p+= strlen(p)+1;
+ }
+
+ free(copy);
+}
+
+static void
+set_integer(const struct cmdinfo *cip, const char *value)
+{
+ *cip->iassignto = dpkg_options_parse_arg_int(cip, value);
+}
+
+static void
+set_pipe(const struct cmdinfo *cip, const char *value)
+{
+ long v;
+
+ v = dpkg_options_parse_arg_int(cip, value);
+
+ statusfd_add(v);
+}
+
+static bool
+is_invoke_action(enum action action)
+{
+ switch (action) {
+ case act_unpack:
+ case act_configure:
+ case act_install:
+ case act_triggers:
+ case act_remove:
+ case act_purge:
+ case act_arch_add:
+ case act_arch_remove:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct invoke_list pre_invoke_hooks = {
+ .head = NULL,
+ .tail = &pre_invoke_hooks.head,
+};
+static struct invoke_list post_invoke_hooks = {
+ .head = NULL,
+ .tail = &post_invoke_hooks.head,
+};
+static struct invoke_list status_loggers = {
+ .head = NULL,
+ .tail = &status_loggers.head,
+};
+
+static void
+set_invoke_hook(const struct cmdinfo *cip, const char *value)
+{
+ struct invoke_list *hook_list = cip->arg_ptr;
+ struct invoke_hook *hook_new;
+
+ hook_new = m_malloc(sizeof(*hook_new));
+ hook_new->command = m_strdup(value);
+ hook_new->next = NULL;
+
+ /* Add the new hook at the tail of the list to preserve the order. */
+ *hook_list->tail = hook_new;
+ hook_list->tail = &hook_new->next;
+}
+
+static void
+run_invoke_hooks(const char *action, struct invoke_list *hook_list)
+{
+ struct invoke_hook *hook;
+
+ setenv("DPKG_HOOK_ACTION", action, 1);
+
+ for (hook = hook_list->head; hook; hook = hook->next) {
+ int status;
+
+ /* XXX: As an optimization, use exec instead if no shell metachar are
+ * used “!$=&|\\`'"^~;<>{}[]()?*#”. */
+ status = system(hook->command);
+ if (status != 0)
+ ohshit(_("error executing hook '%s', exit code %d"), hook->command,
+ status);
+ }
+
+ unsetenv("DPKG_HOOK_ACTION");
+}
+
+static void
+free_invoke_hooks(struct invoke_list *hook_list)
+{
+ struct invoke_hook *hook, *hook_next;
+
+ for (hook = hook_list->head; hook; hook = hook_next) {
+ hook_next = hook->next;
+ free(hook->command);
+ free(hook);
+ }
+}
+
+static int
+run_logger(struct invoke_hook *hook, const char *name)
+{
+ pid_t pid;
+ int p[2];
+
+ m_pipe(p);
+
+ pid = subproc_fork();
+ if (pid == 0) {
+ /* Setup stdin and stdout. */
+ m_dup2(p[0], 0);
+ close(1);
+
+ close(p[0]);
+ close(p[1]);
+
+ command_shell(hook->command, name);
+ }
+ close(p[0]);
+
+ return p[1];
+}
+
+static void
+run_status_loggers(struct invoke_list *hook_list)
+{
+ struct invoke_hook *hook;
+
+ for (hook = hook_list->head; hook; hook = hook->next) {
+ int fd;
+
+ fd = run_logger(hook, _("status logger"));
+ statusfd_add(fd);
+ }
+}
+
+static int
+arch_add(const char *const *argv)
+{
+ struct dpkg_arch *arch;
+ const char *archname = *argv++;
+
+ if (archname == NULL || *argv)
+ badusage(_("--%s takes exactly one argument"), cipaction->olong);
+
+ dpkg_arch_load_list();
+
+ arch = dpkg_arch_add(archname);
+ switch (arch->type) {
+ case DPKG_ARCH_NATIVE:
+ case DPKG_ARCH_FOREIGN:
+ break;
+ case DPKG_ARCH_ILLEGAL:
+ ohshit(_("architecture '%s' is illegal: %s"), archname,
+ dpkg_arch_name_is_illegal(archname));
+ default:
+ ohshit(_("architecture '%s' is reserved and cannot be added"), archname);
+ }
+
+ dpkg_arch_save_list();
+
+ return 0;
+}
+
+static int
+arch_remove(const char *const *argv)
+{
+ const char *archname = *argv++;
+ struct dpkg_arch *arch;
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ if (archname == NULL || *argv)
+ badusage(_("--%s takes exactly one argument"), cipaction->olong);
+
+ modstatdb_open(msdbrw_readonly);
+
+ arch = dpkg_arch_find(archname);
+ if (arch->type != DPKG_ARCH_FOREIGN) {
+ warning(_("cannot remove non-foreign architecture '%s'"), arch->name);
+ return 0;
+ }
+
+ /* Check if it's safe to remove the architecture from the db. */
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (pkg->status < PKG_STAT_HALFINSTALLED)
+ continue;
+ if (pkg->installed.arch == arch) {
+ if (in_force(FORCE_ARCHITECTURE))
+ warning(_("removing architecture '%s' currently in use by database"),
+ arch->name);
+ else
+ ohshit(_("cannot remove architecture '%s' currently in use by the database"),
+ arch->name);
+ break;
+ }
+ }
+ pkg_hash_iter_free(iter);
+
+ dpkg_arch_unmark(arch);
+ dpkg_arch_save_list();
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+int execbackend(const char *const *argv) DPKG_ATTR_NORET;
+int commandfd(const char *const *argv);
+
+/* This table has both the action entries in it and the normal options.
+ * The action entries are made with the ACTION macro, as they all
+ * have a very similar structure. */
+static const struct cmdinfo cmdinfos[]= {
+#define ACTIONBACKEND(longopt, shortopt, backend) \
+ { longopt, shortopt, 0, NULL, NULL, setaction, 0, (void *)backend, execbackend }
+
+ ACTION( "install", 'i', act_install, archivefiles ),
+ ACTION( "unpack", 0, act_unpack, archivefiles ),
+ ACTION( "record-avail", 'A', act_avail, archivefiles ),
+ ACTION( "configure", 0, act_configure, packages ),
+ ACTION( "remove", 'r', act_remove, packages ),
+ ACTION( "purge", 'P', act_purge, packages ),
+ ACTION( "triggers-only", 0, act_triggers, packages ),
+ ACTION( "verify", 'V', act_verify, verify ),
+ ACTIONBACKEND( "listfiles", 'L', DPKGQUERY),
+ ACTIONBACKEND( "status", 's', DPKGQUERY),
+ ACTION( "get-selections", 0, act_getselections, getselections ),
+ ACTION( "set-selections", 0, act_setselections, setselections ),
+ ACTION( "clear-selections", 0, act_clearselections, clearselections ),
+ ACTIONBACKEND( "print-avail", 'p', DPKGQUERY),
+ ACTION( "update-avail", 0, act_avreplace, updateavailable ),
+ ACTION( "merge-avail", 0, act_avmerge, updateavailable ),
+ ACTION( "clear-avail", 0, act_avclear, updateavailable ),
+ ACTION( "forget-old-unavail", 0, act_forgetold, forgetold ),
+ ACTION( "audit", 'C', act_audit, audit ),
+ ACTION( "yet-to-unpack", 0, act_unpackchk, unpackchk ),
+ ACTIONBACKEND( "list", 'l', DPKGQUERY),
+ ACTIONBACKEND( "search", 'S', DPKGQUERY),
+ ACTION_MUX( "assert", 0, act_assert_feature, assert_feature, &assert_feature_name),
+ ACTION( "add-architecture", 0, act_arch_add, arch_add ),
+ ACTION( "remove-architecture", 0, act_arch_remove, arch_remove ),
+ ACTION( "print-architecture", 0, act_printarch, printarch ),
+ ACTION( "print-foreign-architectures", 0, act_printforeignarches, print_foreign_arches ),
+ ACTION( "predep-package", 0, act_predeppackage, predeppackage ),
+ ACTION( "validate-pkgname", 0, act_validate_pkgname, validate_pkgname ),
+ ACTION( "validate-trigname", 0, act_validate_trigname, validate_trigname ),
+ ACTION( "validate-archname", 0, act_validate_archname, validate_archname ),
+ ACTION( "validate-version", 0, act_validate_version, validate_version ),
+ ACTION( "compare-versions", 0, act_cmpversions, cmpversions ),
+/*
+ ACTION( "command-fd", 'c', act_commandfd, commandfd ),
+*/
+ ACTION( "help", '?', act_help, usage),
+ ACTION( "version", 0, act_version, printversion),
+
+ { "pre-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &pre_invoke_hooks },
+ { "post-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &post_invoke_hooks },
+ { "path-exclude", 0, 1, NULL, NULL, set_filter, 0 },
+ { "path-include", 0, 1, NULL, NULL, set_filter, 1 },
+ { "verify-format", 0, 1, NULL, NULL, set_verify_format },
+ { "status-logger", 0, 1, NULL, NULL, set_invoke_hook, 0, &status_loggers },
+ { "status-fd", 0, 1, NULL, NULL, set_pipe, 0 },
+ { "log", 0, 1, NULL, &log_file, NULL, 0 },
+ { "pending", 'a', 0, &f_pending, NULL, NULL, 1 },
+ { "recursive", 'R', 0, &f_recursive, NULL, NULL, 1 },
+ { "no-act", 0, 0, &f_noact, NULL, NULL, 1 },
+ { "dry-run", 0, 0, &f_noact, NULL, NULL, 1 },
+ { "simulate", 0, 0, &f_noact, NULL, NULL, 1 },
+ { "no-pager", 0, 0, NULL, NULL, set_no_pager, 0 },
+ { "no-debsig", 0, 0, &f_nodebsig, NULL, NULL, 1 },
+ /* Alias ('G') for --refuse. */
+ { NULL, 'G', 0, NULL, NULL, reset_force_option, FORCE_DOWNGRADE },
+ { "selected-only", 'O', 0, &f_alsoselect, NULL, NULL, 0 },
+ { "triggers", 0, 0, &f_triggers, NULL, NULL, 1 },
+ { "no-triggers", 0, 0, &f_triggers, NULL, NULL, -1 },
+ /* TODO: Remove ('N') sometime. */
+ { "no-also-select", 'N', 0, &f_alsoselect, NULL, NULL, 0 },
+ { "skip-same-version", 'E', 0, &f_skipsame, NULL, NULL, 1 },
+ { "auto-deconfigure", 'B', 0, &f_autodeconf, NULL, NULL, 1 },
+ { "robot", 0, 0, &f_robot, NULL, NULL, 1 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "abort-after", 0, 1, &errabort, NULL, set_integer, 0 },
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "instdir", 0, 1, NULL, NULL, set_instdir, 0 },
+ { "ignore-depends", 0, 1, NULL, NULL, set_ignore_depends, 0 },
+ { "force", 0, 2, NULL, NULL, set_force_option, 1 },
+ { "refuse", 0, 2, NULL, NULL, set_force_option, 0 },
+ { "no-force", 0, 2, NULL, NULL, set_force_option, 0 },
+ { "debug", 'D', 1, NULL, NULL, set_debug, 0 },
+ ACTIONBACKEND( "build", 'b', BACKEND),
+ ACTIONBACKEND( "contents", 'c', BACKEND),
+ ACTIONBACKEND( "control", 'e', BACKEND),
+ ACTIONBACKEND( "info", 'I', BACKEND),
+ ACTIONBACKEND( "field", 'f', BACKEND),
+ ACTIONBACKEND( "extract", 'x', BACKEND),
+ ACTIONBACKEND( "vextract", 'X', BACKEND),
+ ACTIONBACKEND( "ctrl-tarfile", 0, BACKEND),
+ ACTIONBACKEND( "fsys-tarfile", 0, BACKEND),
+ { NULL, 0, 0, NULL, NULL, NULL, 0 }
+};
+
+int
+execbackend(const char *const *argv)
+{
+ struct command cmd;
+
+ command_init(&cmd, cipaction->arg_ptr, NULL);
+ command_add_arg(&cmd, cipaction->arg_ptr);
+ command_add_arg(&cmd, str_fmt("--%s", cipaction->olong));
+
+ /* Explicitly separate arguments from options as any user-supplied
+ * separator got stripped by the option parser */
+ command_add_arg(&cmd, "--");
+ command_add_argl(&cmd, (const char **)argv);
+
+ command_exec(&cmd);
+}
+
+int
+commandfd(const char *const *argv)
+{
+ struct varbuf linevb = VARBUF_INIT;
+ const char * pipein;
+ const char **newargs = NULL, **endargs;
+ char *ptr, *endptr;
+ FILE *in;
+ long infd;
+ int ret = 0;
+ int c, lno, i;
+ bool skipchar;
+
+ pipein = *argv++;
+ if (pipein == NULL || *argv)
+ badusage(_("--%s takes exactly one argument"), cipaction->olong);
+
+ infd = dpkg_options_parse_arg_int(cipaction, pipein);
+ in = fdopen(infd, "r");
+ if (in == NULL)
+ ohshite(_("couldn't open '%i' for stream"), (int)infd);
+
+ for (;;) {
+ bool mode = false;
+ int argc= 1;
+ lno= 0;
+
+ push_error_context();
+
+ do {
+ c = getc(in);
+ if (c == '\n')
+ lno++;
+ } while (c != EOF && c_isspace(c));
+ if (c == EOF) break;
+ if (c == '#') {
+ do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n');
+ continue;
+ }
+ varbuf_reset(&linevb);
+ do {
+ varbuf_add_char(&linevb, c);
+ c= getc(in);
+ if (c == '\n') lno++;
+
+ /* This isn't fully accurate, but overestimating can't hurt. */
+ if (c_isspace(c))
+ argc++;
+ } while (c != EOF && c != '\n');
+ if (c == EOF)
+ ohshit(_("unexpected end of file before end of line %d"), lno);
+ if (!argc) continue;
+ varbuf_end_str(&linevb);
+ newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1));
+ argc= 1;
+ ptr= linevb.buf;
+ endptr = ptr + linevb.used + 1;
+ skipchar = false;
+ while(ptr < endptr) {
+ if (skipchar) {
+ skipchar = false;
+ } else if (*ptr == '\\') {
+ memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1));
+ endptr--;
+ skipchar = true;
+ continue;
+ } else if (c_isspace(*ptr)) {
+ if (mode == true) {
+ *ptr = '\0';
+ mode = false;
+ }
+ } else {
+ if (mode == false) {
+ newargs[argc]= ptr;
+ argc++;
+ mode = true;
+ }
+ }
+ ptr++;
+ }
+ *ptr = '\0';
+ newargs[argc++] = NULL;
+
+ /* We strdup() each argument, but never free it, because the
+ * error messages contain references back to these strings.
+ * Freeing them, and reusing the memory, would make those
+ * error messages confusing, to say the least. */
+ for(i=1;i<argc;i++)
+ if (newargs[i])
+ newargs[i] = m_strdup(newargs[i]);
+ endargs = newargs;
+
+ setaction(NULL, NULL);
+ dpkg_options_parse((const char *const **)&endargs, cmdinfos, printforhelp);
+ if (!cipaction) badusage(_("need an action option"));
+
+ ret |= cipaction->action(endargs);
+
+ fsys_hash_reset();
+
+ pop_error_context(ehflag_normaltidy);
+ }
+
+ fclose(in);
+
+ return ret;
+}
+
+int main(int argc, const char *const *argv) {
+ char *force_string;
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init("dpkg");
+ set_force_default(FORCE_ALL);
+ dpkg_options_load(DPKG, cmdinfos);
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ /* When running as root, make sure our primary group is also root, so
+ * that files created by maintainer scripts have correct ownership. */
+ if (!in_force(FORCE_NON_ROOT) && getuid() == 0 && getgid() != 0)
+ if (setgid(0) < 0)
+ ohshite(_("cannot set primary group ID to root"));
+
+ if (!cipaction) badusage(_("need an action option"));
+
+ /* Always set environment, to avoid possible security risks. */
+ if (setenv("DPKG_ADMINDIR", dpkg_db_get_dir(), 1) < 0)
+ ohshite(_("unable to setenv for subprocesses"));
+ if (setenv("DPKG_ROOT", dpkg_fsys_get_dir(), 1) < 0)
+ ohshite(_("unable to setenv for subprocesses"));
+ force_string = get_force_string();
+ if (setenv("DPKG_FORCE", force_string, 1) < 0)
+ ohshite(_("unable to setenv for subprocesses"));
+ free(force_string);
+
+ if (!f_triggers)
+ f_triggers = (cipaction->arg_int == act_triggers && *argv) ? -1 : 1;
+
+ if (is_invoke_action(cipaction->arg_int)) {
+ run_invoke_hooks(cipaction->olong, &pre_invoke_hooks);
+ run_status_loggers(&status_loggers);
+ }
+
+ ret = cipaction->action(argv);
+
+ if (is_invoke_action(cipaction->arg_int))
+ run_invoke_hooks(cipaction->olong, &post_invoke_hooks);
+
+ free_invoke_hooks(&pre_invoke_hooks);
+ free_invoke_hooks(&post_invoke_hooks);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return reportbroken_retexitstatus(ret);
+}
diff --git a/src/main/main.h b/src/main/main.h
new file mode 100644
index 0000000..9b7d896
--- /dev/null
+++ b/src/main/main.h
@@ -0,0 +1,305 @@
+/*
+ * dpkg - main program for package management
+ * main.h - external definitions for this program
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2016 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 MAIN_H
+#define MAIN_H
+
+#include <dpkg/debug.h>
+#include <dpkg/pkg-list.h>
+
+#include "force.h"
+#include "actions.h"
+#include "security-mac.h"
+
+/* These two are defined in <dpkg/fsys.h>. */
+struct fsys_namenode_list;
+struct fsys_namenode;
+
+enum pkg_istobe {
+ /** Package is to be left in a normal state. */
+ PKG_ISTOBE_NORMAL,
+ /** Package is to be removed. */
+ PKG_ISTOBE_REMOVE,
+ /** Package is to be installed, configured or triggered. */
+ PKG_ISTOBE_INSTALLNEW,
+ /** Package is to be deconfigured. */
+ PKG_ISTOBE_DECONFIGURE,
+ /** Package is to be checked for Pre-Depends satisfiability. */
+ PKG_ISTOBE_PREINSTALL,
+};
+
+enum pkg_cycle_color {
+ PKG_CYCLE_WHITE,
+ PKG_CYCLE_GRAY,
+ PKG_CYCLE_BLACK,
+};
+
+struct perpackagestate {
+ enum pkg_istobe istobe;
+
+ /** Used during cycle detection. */
+ enum pkg_cycle_color color;
+
+ bool enqueued;
+
+ int replacingfilesandsaid;
+ int cmdline_seen;
+
+ /** Non-NULL iff in trigproc.c:deferred. */
+ struct pkg_list *trigprocdeferred;
+};
+
+extern const char *const statusstrings[];
+
+extern int f_robot;
+extern int f_pending, f_recursive, f_alsoselect, f_skipsame, f_noact;
+extern int f_autodeconf, f_nodebsig;
+extern int f_triggers;
+
+extern bool abort_processing;
+extern int errabort;
+extern struct pkg_list *ignoredependss;
+
+struct invoke_hook {
+ struct invoke_hook *next;
+ char *command;
+};
+
+struct invoke_list {
+ struct invoke_hook *head, **tail;
+};
+
+/* from perpkgstate.c */
+
+void ensure_package_clientdata(struct pkginfo *pkg);
+
+/* from archives.c */
+
+int archivefiles(const char *const *argv);
+void process_archive(const char *filename);
+bool wanttoinstall(struct pkginfo *pkg);
+
+/* from update.c */
+
+int forgetold(const char *const *argv);
+int updateavailable(const char *const *argv);
+
+/* from enquiry.c */
+
+extern const char *assert_feature_name;
+
+int audit(const char *const *argv);
+int unpackchk(const char *const *argv);
+int assert_feature(const char *const *argv);
+int validate_pkgname(const char *const *argv);
+int validate_trigname(const char *const *argv);
+int validate_archname(const char *const *argv);
+int validate_version(const char *const *argv);
+int predeppackage(const char *const *argv);
+int printarch(const char *const *argv);
+int printinstarch(const char *const *argv);
+int print_foreign_arches(const char *const *argv);
+int cmpversions(const char *const *argv);
+
+/* from verify.c */
+
+bool verify_set_output(const char *name);
+int verify(const char *const *argv);
+
+/* from select.c */
+
+int getselections(const char *const *argv);
+int setselections(const char *const *argv);
+int clearselections(const char *const *argv);
+
+/* from packages.c, remove.c and configure.c */
+
+void md5hash(struct pkginfo *pkg, char *hashbuf, const char *fn);
+void enqueue_package(struct pkginfo *pkg);
+void enqueue_package_mark_seen(struct pkginfo *pkg);
+void process_queue(void);
+int packages(const char *const *argv);
+void removal_bulk(struct pkginfo *pkg);
+int conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in);
+
+enum dep_check {
+ DEP_CHECK_HALT = 0,
+ DEP_CHECK_DEFER = 1,
+ DEP_CHECK_OK = 2,
+};
+
+enum dep_check dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
+ struct varbuf *aemsgs);
+enum dep_check breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs);
+
+void deferred_remove(struct pkginfo *pkg);
+void deferred_configure(struct pkginfo *pkg);
+
+/*
+ * During the packages queue processing, the algorithm for deciding what to
+ * configure first is as follows:
+ *
+ * Loop through all packages doing a ‘try 1’ until we've been round and
+ * nothing has been done, then do ‘try 2’, and subsequent ones likewise.
+ * The incrementing of ‘dependtry’ is done by process_queue().
+ *
+ * Try 1:
+ * Are all dependencies of this package done? If so, do it.
+ * Are any of the dependencies missing or the wrong version?
+ * If so, abort (unless --force-depends, in which case defer).
+ * Will we need to configure a package we weren't given as an
+ * argument? If so, abort ─ except if --force-configure-any,
+ * in which case we add the package to the argument list.
+ * If none of the above, defer the package.
+ *
+ * Try 2:
+ * Find a cycle and break it (see above).
+ * Do as for try 1.
+ *
+ * Try 3:
+ * Start processing triggers if necessary.
+ * Do as for try 2.
+ *
+ * Try 4:
+ * Same as for try 3, but check trigger cycles even when deferring
+ * processing due to unsatisfiable dependencies.
+ *
+ * Try 5 (only if --force-depends-version):
+ * Same as for try 2, but don't mind version number in dependencies.
+ *
+ * Try 6 (only if --force-depends):
+ * Do anyway.
+ */
+enum dependtry {
+ DEPEND_TRY_NORMAL = 1,
+ DEPEND_TRY_CYCLES = 2,
+ DEPEND_TRY_TRIGGERS = 3,
+ DEPEND_TRY_TRIGGERS_CYCLES = 4,
+ DEPEND_TRY_FORCE_DEPENDS_VERSION = 5,
+ DEPEND_TRY_FORCE_DEPENDS = 6,
+ DEPEND_TRY_LAST,
+};
+
+extern enum dependtry dependtry;
+extern int sincenothing;
+
+/* from cleanup.c (most of these are declared in archives.h) */
+
+void cu_prermremove(int argc, void **argv);
+
+/* from errors.c */
+
+void print_error_perpackage(const char *emsg, const void *data);
+void print_error_perarchive(const char *emsg, const void *data);
+int reportbroken_retexitstatus(int ret);
+bool skip_due_to_hold(struct pkginfo *pkg);
+
+/* from help.c */
+
+struct stat;
+
+bool ignore_depends(const struct pkginfo *pkg);
+bool force_breaks(struct deppossi *possi);
+bool force_depends(struct deppossi *possi);
+bool force_conflicts(struct deppossi *possi);
+void
+conffile_mark_obsolete(struct pkginfo *pkg, struct fsys_namenode *namenode);
+void pkg_conffiles_mark_old(struct pkginfo *pkg);
+bool find_command(const char *prog);
+void checkpath(void);
+
+struct fsys_namenode *
+namenodetouse(struct fsys_namenode *namenode,
+ struct pkginfo *pkg, struct pkgbin *pkgbin);
+
+int maintscript_installed(struct pkginfo *pkg, const char *scriptname,
+ const char *desc, ...) DPKG_ATTR_SENTINEL;
+int maintscript_new(struct pkginfo *pkg,
+ const char *scriptname, const char *desc,
+ const char *cidir, char *cidirrest, ...)
+ DPKG_ATTR_SENTINEL;
+int maintscript_fallback(struct pkginfo *pkg,
+ const char *scriptname, const char *desc,
+ const char *cidir, char *cidirrest,
+ const char *ifok, const char *iffallback);
+
+/* Callers wanting to run the postinst use these two as they want to postpone
+ * trigger incorporation until after updating the package status. The effect
+ * is that a package can trigger itself. */
+int maintscript_postinst(struct pkginfo *pkg, ...) DPKG_ATTR_SENTINEL;
+void post_postinst_tasks(struct pkginfo *pkg, enum pkgstatus new_status);
+
+void clear_istobes(void);
+bool
+dir_is_used_by_others(struct fsys_namenode *namenode, struct pkginfo *pkg);
+bool
+dir_is_used_by_pkg(struct fsys_namenode *namenode, struct pkginfo *pkg,
+ struct fsys_namenode_list *list);
+bool
+dir_has_conffiles(struct fsys_namenode *namenode, struct pkginfo *pkg);
+
+void log_action(const char *action, struct pkginfo *pkg, struct pkgbin *pkgbin);
+
+/* from trigproc.c */
+
+enum trigproc_type {
+ /** Opportunistic deferred trigger processing. */
+ TRIGPROC_TRY_DEFERRED,
+ /** Opportunistic queued trigger processing. */
+ TRIGPROC_TRY_QUEUED,
+ /** Required trigger processing. */
+ TRIGPROC_REQUIRED,
+};
+
+void trigproc_install_hooks(void);
+void trigproc_populate_deferred(void);
+void trigproc_run_deferred(void);
+void trigproc_reset_cycle(void);
+
+void trigproc(struct pkginfo *pkg, enum trigproc_type type);
+
+void trig_activate_packageprocessing(struct pkginfo *pkg);
+
+/* from depcon.c */
+
+enum which_pkgbin {
+ wpb_installed,
+ wpb_available,
+ wpb_by_istobe,
+};
+
+struct deppossi_pkg_iterator;
+
+struct deppossi_pkg_iterator *
+deppossi_pkg_iter_new(struct deppossi *possi, enum which_pkgbin wpb);
+struct pkginfo *
+deppossi_pkg_iter_next(struct deppossi_pkg_iterator *iter);
+void
+deppossi_pkg_iter_free(struct deppossi_pkg_iterator *iter);
+
+bool depisok(struct dependency *dep, struct varbuf *whynot,
+ struct pkginfo **fixbyrm, struct pkginfo **fixbytrigaw,
+ bool allowunconfigd);
+struct cyclesofarlink;
+bool findbreakcycle(struct pkginfo *pkg);
+void describedepcon(struct varbuf *addto, struct dependency *dep);
+
+#endif /* MAIN_H */
diff --git a/src/main/packages.c b/src/main/packages.c
new file mode 100644
index 0000000..9c4b75c
--- /dev/null
+++ b/src/main/packages.c
@@ -0,0 +1,758 @@
+/*
+ * dpkg - main program for package management
+ * packages.c - common to actions that process packages
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2014 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <string.h>
+#include <fcntl.h>
+#include <dirent.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/pkg-list.h>
+#include <dpkg/pkg-queue.h>
+#include <dpkg/string.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+static struct pkginfo *progress_bytrigproc;
+static struct pkg_queue queue = PKG_QUEUE_INIT;
+
+enum dependtry dependtry = DEPEND_TRY_NORMAL;
+int sincenothing = 0;
+
+void
+enqueue_package(struct pkginfo *pkg)
+{
+ ensure_package_clientdata(pkg);
+ if (pkg->clientdata->enqueued)
+ return;
+ pkg->clientdata->enqueued = true;
+ pkg_queue_push(&queue, pkg);
+}
+
+void
+enqueue_package_mark_seen(struct pkginfo *pkg)
+{
+ enqueue_package(pkg);
+ pkg->clientdata->cmdline_seen++;
+}
+
+static void
+enqueue_pending(void)
+{
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter)) != NULL) {
+ switch (cipaction->arg_int) {
+ case act_configure:
+ if (!(pkg->status == PKG_STAT_UNPACKED ||
+ pkg->status == PKG_STAT_HALFCONFIGURED ||
+ pkg->trigpend_head))
+ continue;
+ if (pkg->want != PKG_WANT_INSTALL &&
+ pkg->want != PKG_WANT_HOLD)
+ continue;
+ break;
+ case act_triggers:
+ if (!pkg->trigpend_head)
+ continue;
+ if (pkg->want != PKG_WANT_INSTALL &&
+ pkg->want != PKG_WANT_HOLD)
+ continue;
+ break;
+ case act_remove:
+ case act_purge:
+ if (pkg->want != PKG_WANT_PURGE) {
+ if (pkg->want != PKG_WANT_DEINSTALL)
+ continue;
+ if (pkg->status == PKG_STAT_CONFIGFILES)
+ continue;
+ }
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ continue;
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+ enqueue_package(pkg);
+ }
+ pkg_hash_iter_free(iter);
+}
+
+static void
+enqueue_specified(const char *const *argv)
+{
+ const char *thisarg;
+
+ while ((thisarg = *argv++) != NULL) {
+ struct pkginfo *pkg;
+
+ pkg = dpkg_options_parse_pkgname(cipaction, thisarg);
+ if (pkg->status == PKG_STAT_NOTINSTALLED &&
+ str_match_end(pkg->set->name, DEBEXT)) {
+ badusage(_("you must specify packages by their own names, "
+ "not by quoting the names of the files they come in"));
+ }
+ enqueue_package_mark_seen(pkg);
+ }
+
+ if (cipaction->arg_int == act_configure)
+ trigproc_populate_deferred();
+}
+
+int
+packages(const char *const *argv)
+{
+ trigproc_install_hooks();
+
+ modstatdb_open(f_noact ? msdbrw_readonly :
+ in_force(FORCE_NON_ROOT) ? msdbrw_write :
+ msdbrw_needsuperuser);
+ checkpath();
+ pkg_infodb_upgrade();
+
+ log_message("startup packages %s", cipaction->olong);
+
+ if (f_pending) {
+ if (*argv)
+ badusage(_("--%s --pending does not take any non-option arguments"),cipaction->olong);
+
+ enqueue_pending();
+ } else {
+ if (!*argv)
+ badusage(_("--%s needs at least one package name argument"), cipaction->olong);
+
+ enqueue_specified(argv);
+ }
+
+ ensure_diversions();
+
+ process_queue();
+ trigproc_run_deferred();
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+void process_queue(void) {
+ struct pkg_list *rundown;
+ struct pkginfo *volatile pkg;
+ volatile enum action action_todo;
+ jmp_buf ejbuf;
+ enum pkg_istobe istobe = PKG_ISTOBE_NORMAL;
+
+ if (abort_processing)
+ return;
+
+ clear_istobes();
+
+ switch (cipaction->arg_int) {
+ case act_triggers:
+ case act_configure:
+ case act_install:
+ istobe = PKG_ISTOBE_INSTALLNEW;
+ break;
+ case act_remove:
+ case act_purge:
+ istobe = PKG_ISTOBE_REMOVE;
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+ for (rundown = queue.head; rundown; rundown = rundown->next) {
+ ensure_package_clientdata(rundown->pkg);
+
+ /* We have processed this package more than once. There are no duplicates
+ * as we make sure of that when enqueuing them. */
+ if (rundown->pkg->clientdata->cmdline_seen > 1) {
+ switch (cipaction->arg_int) {
+ case act_triggers:
+ case act_configure: case act_remove: case act_purge:
+ printf(_("Package %s listed more than once, only processing once.\n"),
+ pkg_name(rundown->pkg, pnaw_nonambig));
+ break;
+ case act_install:
+ printf(_("More than one copy of package %s has been unpacked\n"
+ " in this run ! Only configuring it once.\n"),
+ pkg_name(rundown->pkg, pnaw_nonambig));
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+ }
+ rundown->pkg->clientdata->istobe = istobe;
+ }
+
+ while (!pkg_queue_is_empty(&queue)) {
+ pkg = pkg_queue_pop(&queue);
+ if (!pkg)
+ continue; /* Duplicate, which we removed earlier. */
+
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->enqueued = false;
+
+ action_todo = cipaction->arg_int;
+
+ if (sincenothing++ > queue.length * 3 + 2) {
+ /* Make sure that even if we have exceeded the queue since not having
+ * made any progress, we are not getting stuck trying to progress by
+ * trigger processing, w/o jumping into the next dependtry. */
+ dependtry++;
+ sincenothing = 0;
+ if (dependtry >= DEPEND_TRY_LAST)
+ internerr("exceeded dependtry %d (sincenothing=%d; queue.length=%d)",
+ dependtry, sincenothing, queue.length);
+ } else if (sincenothing > queue.length * 2 + 2) {
+ if (dependtry >= DEPEND_TRY_TRIGGERS &&
+ progress_bytrigproc && progress_bytrigproc->trigpend_head) {
+ enqueue_package(pkg);
+ pkg = progress_bytrigproc;
+ progress_bytrigproc = NULL;
+ action_todo = act_configure;
+ } else {
+ dependtry++;
+ sincenothing = 0;
+ if (dependtry >= DEPEND_TRY_LAST)
+ internerr("exceeded dependtry %d (sincenothing=%d, queue.length=%d)",
+ dependtry, sincenothing, queue.length);
+ }
+ }
+
+ debug(dbg_general, "process queue pkg %s queue.len %d progress %d, try %d",
+ pkg_name(pkg, pnaw_always), queue.length, sincenothing, dependtry);
+
+ if (pkg->status > PKG_STAT_INSTALLED)
+ internerr("package %s status %d is out-of-bounds",
+ pkg_name(pkg, pnaw_always), pkg->status);
+
+ if (setjmp(ejbuf)) {
+ /* Give up on it from the point of view of other packages, i.e. reset
+ * istobe. */
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+
+ pop_error_context(ehflag_bombout);
+ if (abort_processing)
+ return;
+ continue;
+ }
+ push_error_context_jump(&ejbuf, print_error_perpackage,
+ pkg_name(pkg, pnaw_nonambig));
+
+ switch (action_todo) {
+ case act_triggers:
+ if (!pkg->trigpend_head)
+ ohshit(_("package %.250s is not ready for trigger processing\n"
+ " (current status '%.250s' with no pending triggers)"),
+ pkg_name(pkg, pnaw_nonambig), pkg_status_name(pkg));
+ /* Fall through. */
+ case act_install:
+ /* Don't try to configure pkgs that we've just disappeared. */
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ break;
+ /* Fall through. */
+ case act_configure:
+ /* Do whatever is most needed. */
+ if (pkg->trigpend_head)
+ trigproc(pkg, TRIGPROC_TRY_QUEUED);
+ else
+ deferred_configure(pkg);
+ break;
+ case act_remove: case act_purge:
+ deferred_remove(pkg);
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+ m_output(stdout, _("<standard output>"));
+ m_output(stderr, _("<standard error>"));
+
+ pop_error_context(ehflag_normaltidy);
+ }
+
+ if (queue.length)
+ internerr("finished package processing with non-empty queue length %d",
+ queue.length);
+}
+
+/*** Dependency processing - common to --configure and --remove. ***/
+
+/*
+ * The algorithm for deciding what to configure or remove first is as
+ * follows:
+ *
+ * Loop through all packages doing a ‘try 1’ until we've been round and
+ * nothing has been done, then do ‘try 2’ and ‘try 3’ likewise.
+ *
+ * When configuring, in each try we check to see whether all
+ * dependencies of this package are done. If so we do it. If some of
+ * the dependencies aren't done yet but will be later we defer the
+ * package, otherwise it is an error.
+ *
+ * When removing, in each try we check to see whether there are any
+ * packages that would have dependencies missing if we removed this
+ * one. If not we remove it now. If some of these packages are
+ * themselves scheduled for removal we defer the package until they
+ * have been done.
+ *
+ * The criteria for satisfying a dependency vary with the various
+ * tries. In try 1 we treat the dependencies as absolute. In try 2 we
+ * check break any cycles in the dependency graph involving the package
+ * we are trying to process before trying to process the package
+ * normally. In try 3 (which should only be reached if
+ * --force-depends-version is set) we ignore version number clauses in
+ * Depends lines. In try 4 (only reached if --force-depends is set) we
+ * say "ok" regardless.
+ *
+ * If we are configuring and one of the packages we depend on is
+ * awaiting configuration but wasn't specified in the argument list we
+ * will add it to the argument list if --configure-any is specified.
+ * In this case we note this as having "done something" so that we
+ * don't needlessly escalate to higher levels of dependency checking
+ * and breaking.
+ */
+
+enum found_status {
+ FOUND_NONE = 0,
+ FOUND_DEFER = 1,
+ FOUND_FORCED = 2,
+ FOUND_OK = 3,
+};
+
+static enum found_status
+found_forced_on(enum dependtry dependtry_forced)
+{
+ if (dependtry >= dependtry_forced)
+ return FOUND_FORCED;
+ else
+ return FOUND_DEFER;
+}
+
+/*
+ * Return values:
+ * 0: cannot be satisfied.
+ * 1: defer: may be satisfied later, when other packages are better or
+ * at higher dependtry due to --force
+ * will set *fixbytrig to package whose trigger processing would help
+ * if applicable (and leave it alone otherwise).
+ * 2: not satisfied but forcing
+ * (*interestingwarnings >= 0 on exit? caller is to print oemsgs).
+ * 3: satisfied now.
+ */
+static enum found_status
+deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
+ struct pkginfo *removing, struct deppossi *provider,
+ struct pkginfo **fixbytrig,
+ bool *matched, struct deppossi *checkversion,
+ int *interestingwarnings, struct varbuf *oemsgs)
+{
+ enum found_status thisf;
+
+ if (ignore_depends(possdependee)) {
+ debug(dbg_depcondetail," ignoring depended package so ok and found");
+ return FOUND_OK;
+ }
+ thisf = FOUND_NONE;
+ if (possdependee == removing) {
+ if (provider) {
+ varbuf_printf(oemsgs,
+ _(" Package %s which provides %s is to be removed.\n"),
+ pkg_name(possdependee, pnaw_nonambig),
+ provider->ed->name);
+ } else {
+ varbuf_printf(oemsgs, _(" Package %s is to be removed.\n"),
+ pkg_name(possdependee, pnaw_nonambig));
+ }
+
+ *matched = true;
+ debug(dbg_depcondetail," removing possdependee, returning %d",thisf);
+ return thisf;
+ }
+ switch (possdependee->status) {
+ case PKG_STAT_UNPACKED:
+ case PKG_STAT_HALFCONFIGURED:
+ case PKG_STAT_TRIGGERSAWAITED:
+ case PKG_STAT_TRIGGERSPENDING:
+ case PKG_STAT_INSTALLED:
+ if (checkversion) {
+ if (provider) {
+ debug(dbg_depcondetail, " checking package %s provided by pkg %s",
+ checkversion->ed->name, pkg_name(possdependee, pnaw_always));
+ if (!pkg_virtual_deppossi_satisfied(checkversion, provider)) {
+ varbuf_printf(oemsgs,
+ _(" Version of %s on system, provided by %s, is %s.\n"),
+ checkversion->ed->name,
+ pkg_name(possdependee, pnaw_always),
+ versiondescribe(&provider->version, vdew_nonambig));
+ if (in_force(FORCE_DEPENDS_VERSION))
+ thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION);
+ debug(dbg_depcondetail, " bad version");
+ goto unsuitable;
+ }
+ } else {
+ debug(dbg_depcondetail, " checking non-provided pkg %s",
+ pkg_name(possdependee, pnaw_always));
+ if (!versionsatisfied(&possdependee->installed, checkversion)) {
+ varbuf_printf(oemsgs, _(" Version of %s on system is %s.\n"),
+ pkg_name(possdependee, pnaw_nonambig),
+ versiondescribe(&possdependee->installed.version,
+ vdew_nonambig));
+ if (in_force(FORCE_DEPENDS_VERSION))
+ thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION);
+ debug(dbg_depcondetail, " bad version");
+ goto unsuitable;
+ }
+ }
+ }
+ if (possdependee->status == PKG_STAT_INSTALLED ||
+ possdependee->status == PKG_STAT_TRIGGERSPENDING) {
+ debug(dbg_depcondetail," is installed, ok and found");
+ return FOUND_OK;
+ }
+ if (possdependee->status == PKG_STAT_TRIGGERSAWAITED) {
+ if (possdependee->trigaw.head == NULL)
+ internerr("package %s in state %s, has no awaited triggers",
+ pkg_name(possdependee, pnaw_always),
+ pkg_status_name(possdependee));
+
+ if (removing ||
+ !(f_triggers ||
+ (possdependee->clientdata &&
+ possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW))) {
+ if (provider) {
+ varbuf_printf(oemsgs,
+ _(" Package %s which provides %s awaits trigger processing.\n"),
+ pkg_name(possdependee, pnaw_nonambig),
+ provider->ed->name);
+ } else {
+ varbuf_printf(oemsgs,
+ _(" Package %s awaits trigger processing.\n"),
+ pkg_name(possdependee, pnaw_nonambig));
+ }
+ debug(dbg_depcondetail, " triggers-awaited, no fixbytrig");
+ goto unsuitable;
+ }
+ /* We don't check the status of trigaw.head->pend here, just in case
+ * we get into the pathological situation where Triggers-Awaited but
+ * the named package doesn't actually have any pending triggers. In
+ * that case we queue the non-pending package for trigger processing
+ * anyway, and that trigger processing will be a noop except for
+ * sorting out all of the packages which name it in Triggers-Awaited.
+ *
+ * (This situation can only arise if modstatdb_note success in
+ * clearing the triggers-pending status of the pending package
+ * but then fails to go on to update the awaiters.) */
+ *fixbytrig = possdependee->trigaw.head->pend;
+ debug(dbg_depcondetail,
+ " triggers-awaited, fixbytrig '%s', defer",
+ pkg_name(*fixbytrig, pnaw_always));
+ return FOUND_DEFER;
+ }
+ if (possdependee->clientdata &&
+ possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) {
+ debug(dbg_depcondetail," unpacked/halfconfigured, defer");
+ return FOUND_DEFER;
+ } else if (!removing && in_force(FORCE_CONFIGURE_ANY) &&
+ !skip_due_to_hold(possdependee) &&
+ !(possdependee->status == PKG_STAT_HALFCONFIGURED)) {
+ notice(_("also configuring '%s' (required by '%s')"),
+ pkg_name(possdependee, pnaw_nonambig),
+ pkg_name(requiredby, pnaw_nonambig));
+ enqueue_package(possdependee);
+ sincenothing = 0;
+ return FOUND_DEFER;
+ } else {
+ if (provider) {
+ varbuf_printf(oemsgs,
+ _(" Package %s which provides %s is not configured yet.\n"),
+ pkg_name(possdependee, pnaw_nonambig),
+ provider->ed->name);
+ } else {
+ varbuf_printf(oemsgs, _(" Package %s is not configured yet.\n"),
+ pkg_name(possdependee, pnaw_nonambig));
+ }
+
+ debug(dbg_depcondetail, " not configured/able");
+ goto unsuitable;
+ }
+
+ default:
+ if (provider) {
+ varbuf_printf(oemsgs,
+ _(" Package %s which provides %s is not installed.\n"),
+ pkg_name(possdependee, pnaw_nonambig),
+ provider->ed->name);
+ } else {
+ varbuf_printf(oemsgs, _(" Package %s is not installed.\n"),
+ pkg_name(possdependee, pnaw_nonambig));
+ }
+
+ debug(dbg_depcondetail, " not installed");
+ goto unsuitable;
+ }
+
+unsuitable:
+ debug(dbg_depcondetail, " returning %d", thisf);
+ (*interestingwarnings)++;
+
+ return thisf;
+}
+
+static void
+breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok,
+ struct deppossi *breaks, struct pkginfo *broken,
+ struct pkginfo *breaker, struct deppossi *virtbroken)
+{
+ struct varbuf depmsg = VARBUF_INIT;
+
+ debug(dbg_depcondetail, " checking breaker %s virtbroken %s",
+ pkg_name(breaker, pnaw_always),
+ virtbroken ? virtbroken->ed->name : "<none>");
+
+ if (breaker->status == PKG_STAT_NOTINSTALLED ||
+ breaker->status == PKG_STAT_CONFIGFILES)
+ return;
+ if (broken == breaker) return;
+ if (!versionsatisfied(&broken->installed, breaks)) return;
+ /* The test below can only trigger if dep_breaks start having
+ * arch qualifiers different from “any”. */
+ if (!archsatisfied(&broken->installed, breaks))
+ return;
+ if (ignore_depends(breaker)) return;
+ if (virtbroken && ignore_depends(&virtbroken->ed->pkg))
+ return;
+ if (virtbroken && !pkg_virtual_deppossi_satisfied(breaks, virtbroken))
+ return;
+
+ varbufdependency(&depmsg, breaks->up);
+ varbuf_end_str(&depmsg);
+ varbuf_printf(aemsgs, _(" %s (%s) breaks %s and is %s.\n"),
+ pkg_name(breaker, pnaw_nonambig),
+ versiondescribe(&breaker->installed.version, vdew_nonambig),
+ depmsg.buf, gettext(statusstrings[breaker->status]));
+ varbuf_destroy(&depmsg);
+
+ if (virtbroken) {
+ varbuf_printf(aemsgs, _(" %s (%s) provides %s.\n"),
+ pkg_name(broken, pnaw_nonambig),
+ versiondescribe(&broken->installed.version, vdew_nonambig),
+ virtbroken->ed->name);
+ } else if (breaks->verrel != DPKG_RELATION_NONE) {
+ varbuf_printf(aemsgs, _(" Version of %s to be configured is %s.\n"),
+ pkg_name(broken, pnaw_nonambig),
+ versiondescribe(&broken->installed.version, vdew_nonambig));
+ if (in_force(FORCE_DEPENDS_VERSION))
+ return;
+ }
+ if (force_breaks(breaks)) return;
+ *ok = DEP_CHECK_HALT;
+}
+
+static void
+breaks_check_target(struct varbuf *aemsgs, enum dep_check *ok,
+ struct pkginfo *broken, struct pkgset *target,
+ struct deppossi *virtbroken)
+{
+ struct deppossi *possi;
+
+ for (possi = target->depended.installed; possi; possi = possi->rev_next) {
+ if (possi->up->type != dep_breaks) continue;
+ breaks_check_one(aemsgs, ok, possi, broken, possi->up->up, virtbroken);
+ }
+}
+
+enum dep_check
+breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs)
+{
+ struct dependency *dep;
+ struct deppossi *virtbroken;
+ enum dep_check ok = DEP_CHECK_OK;
+
+ debug(dbg_depcon, " checking Breaks");
+
+ breaks_check_target(aemsgs, &ok, pkg, pkg->set, NULL);
+
+ for (dep= pkg->installed.depends; dep; dep= dep->next) {
+ if (dep->type != dep_provides) continue;
+ virtbroken = dep->list;
+ debug(dbg_depcondetail, " checking virtbroken %s", virtbroken->ed->name);
+ breaks_check_target(aemsgs, &ok, pkg, virtbroken->ed, virtbroken);
+ }
+ return ok;
+}
+
+/*
+ * Checks [Pre]-Depends only.
+ */
+enum dep_check
+dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
+ struct varbuf *aemsgs)
+{
+ /* Valid values: 2 = ok, 1 = defer, 0 = halt. */
+ enum dep_check ok;
+ /* Valid values: 0 = none, 1 = defer, 2 = withwarning, 3 = ok. */
+ enum found_status found, thisf;
+ int interestingwarnings;
+ bool matched, anycannotfixbytrig;
+ struct varbuf oemsgs = VARBUF_INIT;
+ struct dependency *dep;
+ struct deppossi *possi, *provider;
+ struct pkginfo *possfixbytrig, *canfixbytrig;
+
+ ok = DEP_CHECK_OK;
+ debug(dbg_depcon,"checking dependencies of %s (- %s)",
+ pkg_name(pkg, pnaw_always),
+ removing ? pkg_name(removing, pnaw_always) : "<none>");
+
+ anycannotfixbytrig = false;
+ canfixbytrig = NULL;
+ for (dep= pkg->installed.depends; dep; dep= dep->next) {
+ if (dep->type != dep_depends && dep->type != dep_predepends) continue;
+ debug(dbg_depcondetail," checking group ...");
+ matched = false;
+ interestingwarnings = 0;
+ varbuf_reset(&oemsgs);
+ found = FOUND_NONE;
+ possfixbytrig = NULL;
+ for (possi = dep->list; found != FOUND_OK && possi; possi = possi->next) {
+ struct deppossi_pkg_iterator *possi_iter;
+ struct pkginfo *pkg_pos;
+
+ debug(dbg_depcondetail," checking possibility -> %s",possi->ed->name);
+ if (possi->cyclebreak) {
+ debug(dbg_depcondetail," break cycle so ok and found");
+ found = FOUND_OK;
+ break;
+ }
+
+ thisf = FOUND_NONE;
+ possi_iter = deppossi_pkg_iter_new(possi, wpb_installed);
+ while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
+ thisf = deppossi_ok_found(pkg_pos, pkg, removing, NULL,
+ &possfixbytrig, &matched, possi,
+ &interestingwarnings, &oemsgs);
+ if (thisf > found)
+ found = thisf;
+ if (found == FOUND_OK)
+ break;
+ }
+ deppossi_pkg_iter_free(possi_iter);
+
+ if (found != FOUND_OK) {
+ for (provider = possi->ed->depended.installed;
+ found != FOUND_OK && provider;
+ provider = provider->rev_next) {
+ if (provider->up->type != dep_provides)
+ continue;
+ debug(dbg_depcondetail, " checking provider %s",
+ pkg_name(provider->up->up, pnaw_always));
+ if (!deparchsatisfied(&provider->up->up->installed, provider->arch,
+ possi)) {
+ debug(dbg_depcondetail, " provider does not satisfy arch");
+ continue;
+ }
+ thisf = deppossi_ok_found(provider->up->up, pkg, removing, provider,
+ &possfixbytrig, &matched, possi,
+ &interestingwarnings, &oemsgs);
+ if (thisf == FOUND_DEFER && provider->up->up == pkg && !removing) {
+ /* IOW, if the pkg satisfies its own dep (via a provide), then
+ * we let it pass, even if it isn't configured yet (as we're
+ * installing it). */
+ thisf = FOUND_OK;
+ }
+ if (thisf > found)
+ found = thisf;
+ }
+ }
+ debug(dbg_depcondetail," found %d",found);
+ if (thisf > found) found= thisf;
+ }
+ if (in_force(FORCE_DEPENDS)) {
+ thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS);
+ if (thisf > found) {
+ found = thisf;
+ debug(dbg_depcondetail, " rescued by force-depends, found %d", found);
+ }
+ }
+ debug(dbg_depcondetail, " found %d matched %d possfixbytrig %s",
+ found, matched,
+ possfixbytrig ? pkg_name(possfixbytrig, pnaw_always) : "-");
+ if (removing && !matched) continue;
+ switch (found) {
+ case FOUND_NONE:
+ anycannotfixbytrig = true;
+ ok = DEP_CHECK_HALT;
+ /* Fall through. */
+ case FOUND_FORCED:
+ varbuf_add_str(aemsgs, " ");
+ varbuf_add_pkgbin_name(aemsgs, pkg, &pkg->installed, pnaw_nonambig);
+ varbuf_add_str(aemsgs, _(" depends on "));
+ varbufdependency(aemsgs, dep);
+ if (interestingwarnings) {
+ /* Don't print the line about the package to be removed if
+ * that's the only line. */
+ varbuf_end_str(&oemsgs);
+ varbuf_add_str(aemsgs, _("; however:\n"));
+ varbuf_add_str(aemsgs, oemsgs.buf);
+ } else {
+ varbuf_add_str(aemsgs, ".\n");
+ }
+ break;
+ case FOUND_DEFER:
+ if (possfixbytrig)
+ canfixbytrig = possfixbytrig;
+ else
+ anycannotfixbytrig = true;
+ if (ok > DEP_CHECK_DEFER)
+ ok = DEP_CHECK_DEFER;
+ break;
+ case FOUND_OK:
+ break;
+ default:
+ internerr("unknown value for found '%d'", found);
+ }
+ }
+ if (ok == DEP_CHECK_HALT &&
+ (pkg->clientdata && pkg->clientdata->istobe == PKG_ISTOBE_REMOVE))
+ ok = DEP_CHECK_DEFER;
+ if (!anycannotfixbytrig && canfixbytrig)
+ progress_bytrigproc = canfixbytrig;
+
+ varbuf_destroy(&oemsgs);
+ debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, (int)aemsgs->used, aemsgs->buf);
+ return ok;
+}
diff --git a/src/main/perpkgstate.c b/src/main/perpkgstate.c
new file mode 100644
index 0000000..7542112
--- /dev/null
+++ b/src/main/perpkgstate.c
@@ -0,0 +1,43 @@
+/*
+ * dpkg - main program for package management
+ * perpkgstate.c - struct perpackagestate and function handling
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
+ * 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 <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+
+#include "main.h"
+
+void
+ensure_package_clientdata(struct pkginfo *pkg)
+{
+ if (pkg->clientdata)
+ return;
+ pkg->clientdata = nfmalloc(sizeof(*pkg->clientdata));
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ pkg->clientdata->color = PKG_CYCLE_WHITE;
+ pkg->clientdata->enqueued = false;
+ pkg->clientdata->replacingfilesandsaid = 0;
+ pkg->clientdata->cmdline_seen = 0;
+ pkg->clientdata->trigprocdeferred = NULL;
+}
diff --git a/src/main/remove.c b/src/main/remove.c
new file mode 100644
index 0000000..2cf6513
--- /dev/null
+++ b/src/main/remove.c
@@ -0,0 +1,688 @@
+/*
+ * dpkg - main program for package management
+ * remove.c - functionality for removing packages
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-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 <errno.h>
+#include <string.h>
+#include <fcntl.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/pkg.h>
+#include <dpkg/path.h>
+#include <dpkg/dir.h>
+#include <dpkg/options.h>
+#include <dpkg/triglib.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+/*
+ * pkgdepcheck may be a virtual pkg.
+ */
+static void checkforremoval(struct pkginfo *pkgtoremove,
+ struct pkgset *pkgdepcheck,
+ enum dep_check *rokp, struct varbuf *raemsgs)
+{
+ struct deppossi *possi;
+ struct pkginfo *depender;
+ enum dep_check ok;
+ struct varbuf_state raemsgs_state;
+
+ for (possi = pkgdepcheck->depended.installed; possi; possi = possi->rev_next) {
+ if (possi->up->type != dep_depends && possi->up->type != dep_predepends) continue;
+ depender= possi->up->up;
+ debug(dbg_depcon, "checking depending package '%s'",
+ pkg_name(depender, pnaw_always));
+ if (depender->status < PKG_STAT_UNPACKED)
+ continue;
+ if (ignore_depends(depender)) {
+ debug(dbg_depcon, "ignoring depending package '%s'",
+ pkg_name(depender, pnaw_always));
+ continue;
+ }
+ if (dependtry >= DEPEND_TRY_CYCLES) {
+ if (findbreakcycle(pkgtoremove))
+ sincenothing = 0;
+ }
+ varbuf_snapshot(raemsgs, &raemsgs_state);
+ ok= dependencies_ok(depender,pkgtoremove,raemsgs);
+ if (ok == DEP_CHECK_HALT &&
+ depender->clientdata &&
+ depender->clientdata->istobe == PKG_ISTOBE_REMOVE)
+ ok = DEP_CHECK_DEFER;
+ if (ok == DEP_CHECK_DEFER)
+ /* Don't burble about reasons for deferral. */
+ varbuf_rollback(&raemsgs_state);
+ if (ok < *rokp) *rokp= ok;
+ }
+}
+
+void deferred_remove(struct pkginfo *pkg) {
+ struct varbuf raemsgs = VARBUF_INIT;
+ struct dependency *dep;
+ enum dep_check rok;
+
+ debug(dbg_general, "deferred_remove package %s",
+ pkg_name(pkg, pnaw_always));
+
+ if (!f_pending && pkg->want != PKG_WANT_UNKNOWN) {
+ if (cipaction->arg_int == act_purge)
+ pkg_set_want(pkg, PKG_WANT_PURGE);
+ else
+ pkg_set_want(pkg, PKG_WANT_DEINSTALL);
+
+ if (!f_noact)
+ modstatdb_note(pkg);
+ }
+
+ ensure_package_clientdata(pkg);
+
+ if (pkg->status == PKG_STAT_NOTINSTALLED) {
+ sincenothing = 0;
+ warning(_("ignoring request to remove %.250s which isn't installed"),
+ pkg_name(pkg, pnaw_nonambig));
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ return;
+ } else if (!f_pending &&
+ pkg->status == PKG_STAT_CONFIGFILES &&
+ cipaction->arg_int != act_purge) {
+ sincenothing = 0;
+ warning(_("ignoring request to remove %.250s, only the config\n"
+ " files of which are on the system; use --purge to remove them too"),
+ pkg_name(pkg, pnaw_nonambig));
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ return;
+ }
+
+ if (pkg->status != PKG_STAT_CONFIGFILES) {
+ if (pkg->installed.essential)
+ forcibleerr(FORCE_REMOVE_ESSENTIAL,
+ _("this is an essential package; it should not be removed"));
+ if (pkg->installed.is_protected)
+ forcibleerr(FORCE_REMOVE_PROTECTED,
+ _("this is a protected package; it should not be removed"));
+ }
+
+ debug(dbg_general, "checking dependencies for remove '%s'",
+ pkg_name(pkg, pnaw_always));
+ rok = DEP_CHECK_OK;
+ checkforremoval(pkg, pkg->set, &rok, &raemsgs);
+ for (dep= pkg->installed.depends; dep; dep= dep->next) {
+ if (dep->type != dep_provides) continue;
+ debug(dbg_depcon, "checking virtual package '%s'", dep->list->ed->name);
+ checkforremoval(pkg, dep->list->ed, &rok, &raemsgs);
+ }
+
+ if (rok == DEP_CHECK_DEFER) {
+ varbuf_destroy(&raemsgs);
+ pkg->clientdata->istobe = PKG_ISTOBE_REMOVE;
+ enqueue_package(pkg);
+ return;
+ } else if (rok == DEP_CHECK_HALT) {
+ sincenothing= 0;
+ varbuf_end_str(&raemsgs);
+ notice(_("dependency problems prevent removal of %s:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), raemsgs.buf);
+ ohshit(_("dependency problems - not removing"));
+ } else if (raemsgs.used) {
+ varbuf_end_str(&raemsgs);
+ notice(_("%s: dependency problems, but removing anyway as you requested:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), raemsgs.buf);
+ }
+ varbuf_destroy(&raemsgs);
+ sincenothing= 0;
+
+ if (pkg->eflag & PKG_EFLAG_REINSTREQ)
+ forcibleerr(FORCE_REMOVE_REINSTREQ,
+ _("package is in a very bad inconsistent state; you should\n"
+ " reinstall it before attempting a removal"));
+
+ ensure_allinstfiles_available();
+ fsys_hash_init();
+
+ if (f_noact) {
+ printf(_("Would remove or purge %s (%s) ...\n"),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ pkg_set_status(pkg, PKG_STAT_NOTINSTALLED);
+ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ return;
+ }
+
+ pkg_conffiles_mark_old(pkg);
+
+ /* Only print and log removal action once. This avoids duplication when
+ * using --remove and --purge in sequence. */
+ if (pkg->status > PKG_STAT_CONFIGFILES) {
+ printf(_("Removing %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ log_action("remove", pkg, &pkg->installed);
+ }
+
+ trig_activate_packageprocessing(pkg);
+ if (pkg->status >= PKG_STAT_HALFCONFIGURED) {
+ static enum pkgstatus oldpkgstatus;
+
+ oldpkgstatus= pkg->status;
+ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(pkg);
+ push_cleanup(cu_prermremove, ~ehflag_normaltidy, 2,
+ (void *)pkg, (void *)&oldpkgstatus);
+ maintscript_installed(pkg, PRERMFILE, "pre-removal", "remove", NULL);
+
+ /* Will turn into ‘half-installed’ soon ... */
+ pkg_set_status(pkg, PKG_STAT_UNPACKED);
+ }
+
+ removal_bulk(pkg);
+}
+
+static void
+push_leftover(struct fsys_namenode_list **leftoverp,
+ struct fsys_namenode *namenode)
+{
+ struct fsys_namenode_list *newentry;
+
+ newentry = nfmalloc(sizeof(*newentry));
+ newentry->next= *leftoverp;
+ newentry->namenode= namenode;
+ *leftoverp= newentry;
+}
+
+static void
+removal_bulk_remove_file(const char *filename, const char *filetype)
+{
+ /* We need the postrm and list files for --purge. */
+ if (strcmp(filetype, LISTFILE) == 0 ||
+ strcmp(filetype, POSTRMFILE) == 0)
+ return;
+
+ debug(dbg_stupidlyverbose, "removal_bulk info not postrm or list");
+
+ if (unlink(filename))
+ ohshite(_("unable to delete control info file '%.250s'"), filename);
+
+ debug(dbg_scripts, "removal_bulk info unlinked %s", filename);
+}
+
+static bool
+removal_bulk_file_is_shared(struct pkginfo *pkg, struct fsys_namenode *namenode)
+{
+ struct fsys_node_pkgs_iter *iter;
+ struct pkginfo *otherpkg;
+ bool shared = false;
+
+ if (pkgset_installed_instances(pkg->set) <= 1)
+ return false;
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((otherpkg = fsys_node_pkgs_iter_next(iter))) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->set != pkg->set)
+ continue;
+
+ debug(dbg_eachfiledetail, "removal_bulk file shared with %s, skipping",
+ pkg_name(otherpkg, pnaw_always));
+ shared = true;
+ break;
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ return shared;
+}
+
+static void
+removal_bulk_remove_files(struct pkginfo *pkg)
+{
+ struct fsys_hash_rev_iter rev_iter;
+ struct fsys_namenode_list *leftover;
+ struct fsys_namenode *namenode;
+ static struct varbuf fnvb;
+ struct varbuf_state fnvb_state;
+ struct stat stab;
+
+ pkg_set_status(pkg, PKG_STAT_HALFINSTALLED);
+ modstatdb_note(pkg);
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+ fsys_hash_rev_iter_init(&rev_iter, pkg->files);
+ leftover = NULL;
+ while ((namenode = fsys_hash_rev_iter_next(&rev_iter))) {
+ struct fsys_namenode *usenode;
+ bool is_dir;
+
+ debug(dbg_eachfile, "removal_bulk '%s' flags=%o",
+ namenode->name, namenode->flags);
+
+ usenode = namenodetouse(namenode, pkg, &pkg->installed);
+
+ varbuf_reset(&fnvb);
+ varbuf_add_str(&fnvb, dpkg_fsys_get_dir());
+ varbuf_add_str(&fnvb, usenode->name);
+ varbuf_end_str(&fnvb);
+ varbuf_snapshot(&fnvb, &fnvb_state);
+
+ is_dir = stat(fnvb.buf, &stab) == 0 && S_ISDIR(stab.st_mode);
+
+ /* A pkgset can share files between its instances that we
+ * don't want to remove, we just want to forget them. This
+ * applies to shared conffiles too. */
+ if (!is_dir && removal_bulk_file_is_shared(pkg, namenode))
+ continue;
+
+ /* Non-shared conffiles are kept. */
+ if (namenode->flags & FNNF_OLD_CONFF) {
+ push_leftover(&leftover, namenode);
+ continue;
+ }
+
+ if (is_dir) {
+ debug(dbg_eachfiledetail, "removal_bulk is a directory");
+ /* Only delete a directory or a link to one if we're the only
+ * package which uses it. Other files should only be listed
+ * in this package (but we don't check). */
+ if (dir_has_conffiles(namenode, pkg)) {
+ push_leftover(&leftover,namenode);
+ continue;
+ }
+ if (dir_is_used_by_pkg(namenode, pkg, leftover)) {
+ push_leftover(&leftover, namenode);
+ continue;
+ }
+ if (dir_is_used_by_others(namenode, pkg))
+ continue;
+
+ if (strcmp(usenode->name, "/.") == 0) {
+ debug(dbg_eachfiledetail,
+ "removal_bulk '%s' root directory, cannot remove", fnvb.buf);
+ push_leftover(&leftover, namenode);
+ continue;
+ }
+ }
+
+ trig_path_activate(usenode, pkg);
+
+ varbuf_rollback(&fnvb_state);
+ varbuf_add_str(&fnvb, DPKGTEMPEXT);
+ varbuf_end_str(&fnvb);
+ debug(dbg_eachfiledetail, "removal_bulk cleaning temp '%s'", fnvb.buf);
+ path_remove_tree(fnvb.buf);
+
+ varbuf_rollback(&fnvb_state);
+ varbuf_add_str(&fnvb, DPKGNEWEXT);
+ varbuf_end_str(&fnvb);
+ debug(dbg_eachfiledetail, "removal_bulk cleaning new '%s'", fnvb.buf);
+ path_remove_tree(fnvb.buf);
+
+ varbuf_rollback(&fnvb_state);
+ varbuf_end_str(&fnvb);
+
+ debug(dbg_eachfiledetail, "removal_bulk removing '%s'", fnvb.buf);
+ if (!rmdir(fnvb.buf) || errno == ENOENT || errno == ELOOP) continue;
+ if (errno == ENOTEMPTY || errno == EEXIST) {
+ debug(dbg_eachfiledetail,
+ "removal_bulk '%s' was not empty, will try again later",
+ fnvb.buf);
+ push_leftover(&leftover,namenode);
+ continue;
+ } else if (errno == EBUSY || errno == EPERM) {
+ warning(_("while removing %.250s, unable to remove directory '%.250s': "
+ "%s - directory may be a mount point?"),
+ pkg_name(pkg, pnaw_nonambig), namenode->name, strerror(errno));
+ push_leftover(&leftover,namenode);
+ continue;
+ }
+ if (errno != ENOTDIR)
+ ohshite(_("cannot remove '%.250s'"), fnvb.buf);
+ debug(dbg_eachfiledetail, "removal_bulk unlinking '%s'", fnvb.buf);
+ if (secure_unlink(fnvb.buf))
+ ohshite(_("unable to securely remove '%.250s'"), fnvb.buf);
+ }
+ write_filelist_except(pkg, &pkg->installed, leftover, 0);
+ maintscript_installed(pkg, POSTRMFILE, "post-removal", "remove", NULL);
+
+ trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed, TRIGGERSCIFILE),
+ trig_cicb_interest_delete, NULL, pkg, &pkg->installed);
+ trig_file_interests_save();
+
+ debug(dbg_general, "removal_bulk cleaning info directory");
+ pkg_infodb_foreach(pkg, &pkg->installed, removal_bulk_remove_file);
+ dir_sync_path(pkg_infodb_get_dir());
+
+ pkg_set_status(pkg, PKG_STAT_CONFIGFILES);
+ pkg->installed.essential = false;
+ pkg->installed.is_protected = false;
+ modstatdb_note(pkg);
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+}
+
+static void removal_bulk_remove_leftover_dirs(struct pkginfo *pkg) {
+ struct fsys_hash_rev_iter rev_iter;
+ struct fsys_namenode_list *leftover;
+ struct fsys_namenode *namenode;
+ static struct varbuf fnvb;
+ struct stat stab;
+
+ /* We may have modified this previously. */
+ ensure_packagefiles_available(pkg);
+
+ modstatdb_note(pkg);
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+ fsys_hash_rev_iter_init(&rev_iter, pkg->files);
+ leftover = NULL;
+ while ((namenode = fsys_hash_rev_iter_next(&rev_iter))) {
+ struct fsys_namenode *usenode;
+
+ debug(dbg_eachfile, "removal_bulk '%s' flags=%o",
+ namenode->name, namenode->flags);
+ if (namenode->flags & FNNF_OLD_CONFF) {
+ /* This can only happen if removal_bulk_remove_configfiles() got
+ * interrupted half way. */
+ debug(dbg_eachfiledetail, "removal_bulk expecting only left over dirs, "
+ "ignoring conffile '%s'", namenode->name);
+ continue;
+ }
+
+ usenode = namenodetouse(namenode, pkg, &pkg->installed);
+
+ varbuf_reset(&fnvb);
+ varbuf_add_str(&fnvb, dpkg_fsys_get_dir());
+ varbuf_add_str(&fnvb, usenode->name);
+ varbuf_end_str(&fnvb);
+
+ if (!stat(fnvb.buf,&stab) && S_ISDIR(stab.st_mode)) {
+ debug(dbg_eachfiledetail, "removal_bulk is a directory");
+ /* Only delete a directory or a link to one if we're the only
+ * package which uses it. Other files should only be listed
+ * in this package (but we don't check). */
+ if (dir_is_used_by_pkg(namenode, pkg, leftover)) {
+ push_leftover(&leftover, namenode);
+ continue;
+ }
+ if (dir_is_used_by_others(namenode, pkg))
+ continue;
+
+ if (strcmp(usenode->name, "/.") == 0) {
+ debug(dbg_eachfiledetail,
+ "removal_bulk '%s' root directory, cannot remove", fnvb.buf);
+ push_leftover(&leftover, namenode);
+ continue;
+ }
+ }
+
+ trig_path_activate(usenode, pkg);
+
+ debug(dbg_eachfiledetail, "removal_bulk removing '%s'", fnvb.buf);
+ if (!rmdir(fnvb.buf) || errno == ENOENT || errno == ELOOP) continue;
+ if (errno == ENOTEMPTY || errno == EEXIST) {
+ warning(_("while removing %.250s, directory '%.250s' not empty so not removed"),
+ pkg_name(pkg, pnaw_nonambig), namenode->name);
+ push_leftover(&leftover,namenode);
+ continue;
+ } else if (errno == EBUSY || errno == EPERM) {
+ warning(_("while removing %.250s, unable to remove directory '%.250s': "
+ "%s - directory may be a mount point?"),
+ pkg_name(pkg, pnaw_nonambig), namenode->name, strerror(errno));
+ push_leftover(&leftover,namenode);
+ continue;
+ }
+ if (errno != ENOTDIR)
+ ohshite(_("cannot remove '%.250s'"), fnvb.buf);
+
+ if (lstat(fnvb.buf, &stab) == 0 && S_ISLNK(stab.st_mode)) {
+ debug(dbg_eachfiledetail, "removal_bulk is a symlink to a directory");
+
+ if (unlink(fnvb.buf))
+ ohshite(_("cannot remove '%.250s'"), fnvb.buf);
+
+ continue;
+ }
+
+ push_leftover(&leftover,namenode);
+ }
+ write_filelist_except(pkg, &pkg->installed, leftover, 0);
+
+ modstatdb_note(pkg);
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+}
+
+static void removal_bulk_remove_configfiles(struct pkginfo *pkg) {
+ static const char *const removeconffexts[] = { REMOVECONFFEXTS, NULL };
+ int rc;
+ int conffnameused, conffbasenamelen;
+ char *conffbasename;
+ struct conffile *conff, **lconffp;
+ struct fsys_namenode_list *searchfile;
+ DIR *dsd;
+ struct dirent *de;
+ char *p;
+ const char *const *ext;
+
+ printf(_("Purging configuration files for %s (%s) ...\n"),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ log_action("purge", pkg, &pkg->installed);
+ trig_activate_packageprocessing(pkg);
+
+ /* We may have modified this above. */
+ ensure_packagefiles_available(pkg);
+
+ /* We're about to remove the configuration, so remove the note
+ * about which version it was ... */
+ dpkg_version_blank(&pkg->configversion);
+ modstatdb_note(pkg);
+
+ /* Remove from our list any conffiles that aren't ours any more or
+ * are involved in diversions, except if we are the package doing the
+ * diverting. */
+ for (lconffp = &pkg->installed.conffiles; (conff = *lconffp) != NULL; ) {
+ for (searchfile = pkg->files;
+ searchfile && strcmp(searchfile->namenode->name,conff->name);
+ searchfile= searchfile->next);
+ if (!searchfile) {
+ debug(dbg_conff, "removal_bulk conffile not ours any more '%s'",
+ conff->name);
+ *lconffp= conff->next;
+ } else if (searchfile->namenode->divert &&
+ (searchfile->namenode->divert->camefrom ||
+ (searchfile->namenode->divert->useinstead &&
+ searchfile->namenode->divert->pkgset != pkg->set))) {
+ debug(dbg_conff, "removal_bulk conffile '%s' ignored due to diversion",
+ conff->name);
+ *lconffp= conff->next;
+ } else {
+ debug(dbg_conffdetail, "removal_bulk set to new conffile '%s'",
+ conff->name);
+ conff->hash = NEWCONFFILEFLAG;
+ lconffp= &conff->next;
+ }
+ }
+ modstatdb_note(pkg);
+
+ for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
+ struct fsys_namenode *namenode, *usenode;
+ static struct varbuf fnvb, removevb;
+ struct varbuf_state removevb_state;
+
+ if (conff->obsolete) {
+ debug(dbg_conffdetail, "removal_bulk conffile obsolete %s",
+ conff->name);
+ }
+ varbuf_reset(&fnvb);
+ rc = conffderef(pkg, &fnvb, conff->name);
+ debug(dbg_conffdetail, "removal_bulk conffile '%s' (= '%s')",
+ conff->name, rc == -1 ? "<rc == -1>" : fnvb.buf);
+ if (rc == -1)
+ continue;
+
+ namenode = fsys_hash_find_node(conff->name, 0);
+ usenode = namenodetouse(namenode, pkg, &pkg->installed);
+
+ trig_path_activate(usenode, pkg);
+
+ conffnameused = fnvb.used;
+ if (unlink(fnvb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("cannot remove old config file '%.250s' (= '%.250s')"),
+ conff->name, fnvb.buf);
+ p= strrchr(fnvb.buf,'/'); if (!p) continue;
+ *p = '\0';
+ varbuf_reset(&removevb);
+ varbuf_add_dir(&removevb, fnvb.buf);
+ varbuf_end_str(&removevb);
+ varbuf_snapshot(&removevb, &removevb_state);
+
+ dsd= opendir(removevb.buf);
+ if (!dsd) {
+ int e=errno;
+ debug(dbg_conffdetail, "removal_bulk conffile no dsd %s %s",
+ fnvb.buf, strerror(e)); errno= e;
+ if (errno == ENOENT || errno == ENOTDIR) continue;
+ ohshite(_("cannot read config file directory '%.250s' (from '%.250s')"),
+ fnvb.buf, conff->name);
+ }
+ debug(dbg_conffdetail, "removal_bulk conffile cleaning dsd %s", fnvb.buf);
+ push_cleanup(cu_closedir, ~0, 1, (void *)dsd);
+ *p= '/';
+ conffbasenamelen= strlen(++p);
+ conffbasename= fnvb.buf+conffnameused-conffbasenamelen;
+ while ((de = readdir(dsd)) != NULL) {
+ debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry='%s'"
+ " conffbasename='%s' conffnameused=%d conffbasenamelen=%d",
+ de->d_name, conffbasename, conffnameused, conffbasenamelen);
+ if (strncmp(de->d_name, conffbasename, conffbasenamelen) == 0) {
+ debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry starts right");
+ for (ext= removeconffexts; *ext; ext++)
+ if (strcmp(*ext, de->d_name + conffbasenamelen) == 0)
+ goto yes_remove;
+ p= de->d_name+conffbasenamelen;
+ if (*p++ == '~') {
+ while (*p && c_isdigit(*p))
+ p++;
+ if (*p == '~' && !*++p) goto yes_remove;
+ }
+ }
+ debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry starts wrong");
+ if (de->d_name[0] == '#' &&
+ strncmp(de->d_name + 1, conffbasename, conffbasenamelen) == 0 &&
+ strcmp(de->d_name + 1 + conffbasenamelen, "#") == 0)
+ goto yes_remove;
+ debug(dbg_stupidlyverbose, "removal_bulk conffile dsd entry not it");
+ continue;
+ yes_remove:
+ varbuf_rollback(&removevb_state);
+ varbuf_add_str(&removevb, de->d_name);
+ varbuf_end_str(&removevb);
+ debug(dbg_conffdetail, "removal_bulk conffile dsd entry removing '%s'",
+ removevb.buf);
+ if (unlink(removevb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("cannot remove old backup config file '%.250s' (of '%.250s')"),
+ removevb.buf, conff->name);
+ }
+ pop_cleanup(ehflag_normaltidy); /* closedir */
+ }
+
+ /* Remove the conffiles from the file list file. */
+ write_filelist_except(pkg, &pkg->installed, pkg->files,
+ FNNF_OLD_CONFF);
+
+ pkg->installed.conffiles = NULL;
+ modstatdb_note(pkg);
+
+ maintscript_installed(pkg, POSTRMFILE, "post-removal", "purge", NULL);
+}
+
+/*
+ * This is used both by deferred_remove() in this file, and at the end of
+ * process_archive() in archives.c if it needs to finish removing a
+ * conflicting package.
+ */
+void removal_bulk(struct pkginfo *pkg) {
+ bool foundpostrm;
+
+ debug(dbg_general, "removal_bulk package %s", pkg_name(pkg, pnaw_always));
+
+ if (pkg->status == PKG_STAT_HALFINSTALLED ||
+ pkg->status == PKG_STAT_UNPACKED) {
+ removal_bulk_remove_files(pkg);
+ }
+
+ foundpostrm = pkg_infodb_has_file(pkg, &pkg->installed, POSTRMFILE);
+
+ debug(dbg_general, "removal_bulk purging? foundpostrm=%d",foundpostrm);
+
+ if (!foundpostrm && !pkg->installed.conffiles) {
+ /* If there are no config files and no postrm script then we
+ * go straight into ‘purge’. */
+ debug(dbg_general, "removal_bulk no postrm, no conffiles, purging");
+
+ pkg_set_want(pkg, PKG_WANT_PURGE);
+ dpkg_version_blank(&pkg->configversion);
+ } else if (pkg->want == PKG_WANT_PURGE) {
+ removal_bulk_remove_configfiles(pkg);
+ }
+
+ /* I.e., either of the two branches above. */
+ if (pkg->want == PKG_WANT_PURGE) {
+ const char *filename;
+
+ /* Retry empty directories, and warn on any leftovers that aren't. */
+ removal_bulk_remove_leftover_dirs(pkg);
+
+ filename = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
+ debug(dbg_general, "removal_bulk purge done, removing list '%s'",
+ filename);
+ if (unlink(filename) && errno != ENOENT)
+ ohshite(_("cannot remove old files list"));
+
+ filename = pkg_infodb_get_file(pkg, &pkg->installed, POSTRMFILE);
+ debug(dbg_general, "removal_bulk purge done, removing postrm '%s'",
+ filename);
+ if (unlink(filename) && errno != ENOENT)
+ ohshite(_("can't remove old postrm script"));
+
+ pkg_set_status(pkg, PKG_STAT_NOTINSTALLED);
+ pkg_set_want(pkg, PKG_WANT_UNKNOWN);
+
+ /* This will mess up reverse links, but if we follow them
+ * we won't go back because pkg->status is PKG_STAT_NOTINSTALLED. */
+ pkgbin_blank(&pkg->installed);
+ }
+
+ pkg_reset_eflags(pkg);
+ modstatdb_note(pkg);
+
+ debug(dbg_general, "removal done");
+}
diff --git a/src/main/script.c b/src/main/script.c
new file mode 100644
index 0000000..b4f369d
--- /dev/null
+++ b/src/main/script.c
@@ -0,0 +1,399 @@
+/*
+ * dpkg - main program for package management
+ * script.c - maintainer script routines
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifdef WITH_LIBSELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include <dpkg/i18n.h>
+#include <dpkg/debug.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/pkg.h>
+#include <dpkg/subproc.h>
+#include <dpkg/command.h>
+#include <dpkg/triglib.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+void
+post_postinst_tasks(struct pkginfo *pkg, enum pkgstatus new_status)
+{
+ if (new_status < PKG_STAT_TRIGGERSAWAITED)
+ pkg_set_status(pkg, new_status);
+ else if (pkg->trigaw.head)
+ pkg_set_status(pkg, PKG_STAT_TRIGGERSAWAITED);
+ else if (pkg->trigpend_head)
+ pkg_set_status(pkg, PKG_STAT_TRIGGERSPENDING);
+ else
+ pkg_set_status(pkg, PKG_STAT_INSTALLED);
+ modstatdb_note(pkg);
+
+ debug(dbg_triggersdetail, "post_postinst_tasks - trig_incorporate");
+ trig_incorporate(modstatdb_get_status());
+}
+
+static void
+post_script_tasks(void)
+{
+ debug(dbg_triggersdetail, "post_script_tasks - ensure_diversions");
+ ensure_diversions();
+
+ debug(dbg_triggersdetail, "post_script_tasks - trig_incorporate");
+ trig_incorporate(modstatdb_get_status());
+}
+
+static void
+cu_post_script_tasks(int argc, void **argv)
+{
+ post_script_tasks();
+}
+
+static void
+setexecute(const char *path, struct stat *stab)
+{
+ if ((stab->st_mode & 0555) == 0555)
+ return;
+ if (!chmod(path, 0755))
+ return;
+ ohshite(_("unable to set execute permissions on '%.250s'"), path);
+}
+
+/**
+ * Returns the path to the script inside the chroot.
+ */
+static const char *
+maintscript_pre_exec(struct command *cmd)
+{
+ const char *instdir = dpkg_fsys_get_dir();
+ const char *admindir = dpkg_db_get_dir();
+ const char *changedir;
+ size_t instdirlen = strlen(instdir);
+
+ if (instdirlen > 0 && in_force(FORCE_SCRIPT_CHROOTLESS))
+ changedir = instdir;
+ else
+ changedir = "/";
+
+ if (instdirlen > 0 && !in_force(FORCE_SCRIPT_CHROOTLESS)) {
+ int rc;
+
+ if (strncmp(admindir, instdir, instdirlen) != 0)
+ ohshit(_("admindir must be inside instdir for dpkg to work properly"));
+ if (setenv("DPKG_ADMINDIR", admindir + instdirlen, 1) < 0)
+ ohshite(_("unable to setenv for subprocesses"));
+ if (setenv("DPKG_ROOT", "", 1) < 0)
+ ohshite(_("unable to setenv for subprocesses"));
+
+ rc = chroot(instdir);
+ if (rc && in_force(FORCE_NON_ROOT) && errno == EPERM)
+ ohshit(_("not enough privileges to change root "
+ "directory with --force-not-root, consider "
+ "using --force-script-chrootless?"));
+ else if (rc)
+ ohshite(_("failed to chroot to '%.250s'"), instdir);
+ }
+ /* Switch to a known good directory to give the maintainer script
+ * a saner environment, also needed after the chroot(). */
+ if (chdir(changedir))
+ ohshite(_("failed to chdir to '%.255s'"), changedir);
+ if (debug_has_flag(dbg_scripts)) {
+ struct varbuf args = VARBUF_INIT;
+ const char **argv = cmd->argv;
+
+ while (*++argv) {
+ varbuf_add_char(&args, ' ');
+ varbuf_add_str(&args, *argv);
+ }
+ varbuf_end_str(&args);
+ debug(dbg_scripts, "fork/exec %s (%s )", cmd->filename,
+ args.buf);
+ varbuf_destroy(&args);
+ }
+ if (instdirlen == 0 || in_force(FORCE_SCRIPT_CHROOTLESS))
+ return cmd->filename;
+
+ if (strlen(cmd->filename) < instdirlen)
+ internerr("maintscript name '%s' length < instdir length %zd",
+ cmd->filename, instdirlen);
+
+ return cmd->filename + instdirlen;
+}
+
+/**
+ * Set a new security execution context for the maintainer script.
+ *
+ * Try to create a new execution context based on the current one and the
+ * specific maintainer script filename. If it's the same as the current
+ * one, use the given fallback.
+ */
+static int
+maintscript_set_exec_context(struct command *cmd)
+{
+#ifdef WITH_LIBSELINUX
+ return setexecfilecon(cmd->filename, "dpkg_script_t");
+#else
+ return 0;
+#endif
+}
+
+static int
+maintscript_exec(struct pkginfo *pkg, struct pkgbin *pkgbin,
+ struct command *cmd, struct stat *stab, int warn)
+{
+ pid_t pid;
+ int rc;
+
+ setexecute(cmd->filename, stab);
+
+ push_cleanup(cu_post_script_tasks, ehflag_bombout, 0);
+
+ pid = subproc_fork();
+ if (pid == 0) {
+ char *pkg_count;
+ const char *maintscript_debug;
+
+ pkg_count = str_fmt("%d", pkgset_installed_instances(pkg->set));
+
+ maintscript_debug = debug_has_flag(dbg_scripts) ? "1" : "0";
+
+ if (setenv("DPKG_MAINTSCRIPT_PACKAGE", pkg->set->name, 1) ||
+ setenv("DPKG_MAINTSCRIPT_PACKAGE_REFCOUNT", pkg_count, 1) ||
+ setenv("DPKG_MAINTSCRIPT_ARCH", pkgbin->arch->name, 1) ||
+ setenv("DPKG_MAINTSCRIPT_NAME", cmd->argv[0], 1) ||
+ setenv("DPKG_MAINTSCRIPT_DEBUG", maintscript_debug, 1) ||
+ setenv("DPKG_RUNNING_VERSION", PACKAGE_VERSION, 1))
+ ohshite(_("unable to setenv for maintainer script"));
+
+ cmd->filename = cmd->argv[0] = maintscript_pre_exec(cmd);
+
+ if (maintscript_set_exec_context(cmd) < 0)
+ ohshite(_("cannot set security execution context for "
+ "maintainer script"));
+
+ command_exec(cmd);
+ }
+ subproc_signals_ignore(cmd->name);
+ rc = subproc_reap(pid, cmd->name, warn);
+ subproc_signals_restore();
+
+ pop_cleanup(ehflag_normaltidy);
+
+ return rc;
+}
+
+static int
+vmaintscript_installed(struct pkginfo *pkg, const char *scriptname,
+ const char *desc, va_list args)
+{
+ struct command cmd;
+ const char *scriptpath;
+ struct stat stab;
+ char *buf;
+
+ scriptpath = pkg_infodb_get_file(pkg, &pkg->installed, scriptname);
+ m_asprintf(&buf, _("installed %s package %s script"),
+ pkg_name(pkg, pnaw_nonambig), desc);
+
+ command_init(&cmd, scriptpath, buf);
+ command_add_arg(&cmd, scriptname);
+ command_add_argv(&cmd, args);
+
+ if (stat(scriptpath, &stab)) {
+ command_destroy(&cmd);
+
+ if (errno == ENOENT) {
+ debug(dbg_scripts,
+ "vmaintscript_installed nonexistent %s",
+ scriptname);
+ free(buf);
+ return 0;
+ }
+ ohshite(_("unable to stat %s '%.250s'"), buf, scriptpath);
+ }
+ maintscript_exec(pkg, &pkg->installed, &cmd, &stab, 0);
+
+ command_destroy(&cmd);
+ free(buf);
+
+ return 1;
+}
+
+/*
+ * All ...'s in maintscript_* are const char *'s.
+ */
+
+int
+maintscript_installed(struct pkginfo *pkg, const char *scriptname,
+ const char *desc, ...)
+{
+ va_list args;
+ int rc;
+
+ va_start(args, desc);
+ rc = vmaintscript_installed(pkg, scriptname, desc, args);
+ va_end(args);
+
+ if (rc)
+ post_script_tasks();
+
+ return rc;
+}
+
+int
+maintscript_postinst(struct pkginfo *pkg, ...)
+{
+ va_list args;
+ int rc;
+
+ va_start(args, pkg);
+ rc = vmaintscript_installed(pkg, POSTINSTFILE, "post-installation", args);
+ va_end(args);
+
+ if (rc)
+ ensure_diversions();
+
+ return rc;
+}
+
+int
+maintscript_new(struct pkginfo *pkg, const char *scriptname,
+ const char *desc, const char *cidir, char *cidirrest, ...)
+{
+ struct command cmd;
+ struct stat stab;
+ va_list args;
+ char *buf;
+
+ strcpy(cidirrest, scriptname);
+ m_asprintf(&buf, _("new %s package %s script"),
+ pkg_name(pkg, pnaw_nonambig), desc);
+
+ va_start(args, cidirrest);
+ command_init(&cmd, cidir, buf);
+ command_add_arg(&cmd, scriptname);
+ command_add_argv(&cmd, args);
+ va_end(args);
+
+ if (stat(cidir, &stab)) {
+ command_destroy(&cmd);
+
+ if (errno == ENOENT) {
+ debug(dbg_scripts,
+ "maintscript_new nonexistent %s '%s'",
+ scriptname, cidir);
+ free(buf);
+ return 0;
+ }
+ ohshite(_("unable to stat %s '%.250s'"), buf, cidir);
+ }
+ maintscript_exec(pkg, &pkg->available, &cmd, &stab, 0);
+
+ command_destroy(&cmd);
+ free(buf);
+ post_script_tasks();
+
+ return 1;
+}
+
+int
+maintscript_fallback(struct pkginfo *pkg,
+ const char *scriptname, const char *desc,
+ const char *cidir, char *cidirrest,
+ const char *ifok, const char *iffallback)
+{
+ struct command cmd;
+ const char *oldscriptpath;
+ struct stat stab;
+ char *buf;
+
+ oldscriptpath = pkg_infodb_get_file(pkg, &pkg->installed, scriptname);
+ m_asprintf(&buf, _("old %s package %s script"),
+ pkg_name(pkg, pnaw_nonambig), desc);
+
+ command_init(&cmd, oldscriptpath, buf);
+ command_add_args(&cmd, scriptname, ifok,
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+
+ if (stat(oldscriptpath, &stab)) {
+ if (errno == ENOENT) {
+ debug(dbg_scripts,
+ "maintscript_fallback nonexistent %s '%s'",
+ scriptname, oldscriptpath);
+ command_destroy(&cmd);
+ free(buf);
+ return 0;
+ }
+ warning(_("unable to stat %s '%.250s': %s"),
+ cmd.name, oldscriptpath, strerror(errno));
+ } else {
+ if (!maintscript_exec(pkg, &pkg->installed, &cmd, &stab, SUBPROC_WARN)) {
+ command_destroy(&cmd);
+ free(buf);
+ post_script_tasks();
+ return 1;
+ }
+ }
+ notice(_("trying script from the new package instead ..."));
+
+ strcpy(cidirrest, scriptname);
+ m_asprintf(&buf, _("new %s package %s script"),
+ pkg_name(pkg, pnaw_nonambig), desc);
+
+ command_destroy(&cmd);
+ command_init(&cmd, cidir, buf);
+ command_add_args(&cmd, scriptname, iffallback,
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+
+ if (stat(cidir, &stab)) {
+ command_destroy(&cmd);
+
+ if (errno == ENOENT)
+ ohshit(_("there is no script in the new version of the package - giving up"));
+ else
+ ohshite(_("unable to stat %s '%.250s'"), buf, cidir);
+ }
+
+ maintscript_exec(pkg, &pkg->available, &cmd, &stab, 0);
+ notice(_("... it looks like that went OK"));
+
+ command_destroy(&cmd);
+ free(buf);
+ post_script_tasks();
+
+ return 1;
+}
diff --git a/src/main/select.c b/src/main/select.c
new file mode 100644
index 0000000..de8febd
--- /dev/null
+++ b/src/main/select.c
@@ -0,0 +1,242 @@
+/*
+ * dpkg - main program for package management
+ * select.c - by-hand (rather than dselect-based) package selection
+ *
+ * Copyright © 1995,1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2015 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <fnmatch.h>
+#include <string.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/pkg-array.h>
+#include <dpkg/pkg-show.h>
+#include <dpkg/pkg-spec.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+
+static void getsel1package(struct pkginfo *pkg) {
+ const char *pkgname;
+ int l;
+
+ if (pkg->want == PKG_WANT_UNKNOWN)
+ return;
+ pkgname = pkg_name(pkg, pnaw_nonambig);
+ l = strlen(pkgname);
+ l >>= 3;
+ l = 6 - l;
+ if (l < 1)
+ l = 1;
+ printf("%s%.*s%s\n", pkgname, l, "\t\t\t\t\t\t", pkg_want_name(pkg));
+}
+
+int
+getselections(const char *const *argv)
+{
+ struct pkg_array array;
+ struct pkginfo *pkg;
+ const char *thisarg;
+ int i, found;
+
+ modstatdb_open(msdbrw_readonly);
+
+ pkg_array_init_from_hash(&array);
+ pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
+
+ if (!*argv) {
+ for (i = 0; i < array.n_pkgs; i++) {
+ pkg = array.pkgs[i];
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ continue;
+ getsel1package(pkg);
+ }
+ } else {
+ while ((thisarg= *argv++)) {
+ struct pkg_spec pkgspec;
+
+ found= 0;
+ pkg_spec_init(&pkgspec, PKG_SPEC_PATTERNS | PKG_SPEC_ARCH_WILDCARD);
+ pkg_spec_parse(&pkgspec, thisarg);
+
+ for (i = 0; i < array.n_pkgs; i++) {
+ pkg = array.pkgs[i];
+ if (!pkg_spec_match_pkg(&pkgspec, pkg, &pkg->installed))
+ continue;
+ getsel1package(pkg); found++;
+ }
+ if (!found)
+ notice(_("no packages found matching %s"), thisarg);
+
+ pkg_spec_destroy(&pkgspec);
+ }
+ }
+
+ m_output(stdout, _("<standard output>"));
+ m_output(stderr, _("<standard error>"));
+
+ pkg_array_destroy(&array);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+int
+setselections(const char *const *argv)
+{
+ enum modstatdb_rw msdbflags;
+ const struct namevalue *nv;
+ struct pkginfo *pkg;
+ int c, lno;
+ struct varbuf namevb = VARBUF_INIT;
+ struct varbuf selvb = VARBUF_INIT;
+ bool db_possibly_outdated = false;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ msdbflags = msdbrw_available_readonly;
+ if (f_noact)
+ msdbflags |= msdbrw_readonly;
+ else
+ msdbflags |= msdbrw_write;
+
+ modstatdb_open(msdbflags);
+ pkg_infodb_upgrade();
+
+ lno= 1;
+ for (;;) {
+ struct dpkg_error err;
+
+ do {
+ c = getchar();
+ if (c == '\n')
+ lno++;
+ } while (c != EOF && c_isspace(c));
+ if (c == EOF) break;
+ if (c == '#') {
+ do { c= getchar(); if (c == '\n') lno++; } while (c != EOF && c != '\n');
+ continue;
+ }
+
+ varbuf_reset(&namevb);
+ while (!c_isspace(c)) {
+ varbuf_add_char(&namevb, c);
+ c= getchar();
+ if (c == EOF)
+ ohshit(_("unexpected end of file in package name at line %d"), lno);
+ if (c == '\n') ohshit(_("unexpected end of line in package name at line %d"),lno);
+ }
+ varbuf_end_str(&namevb);
+
+ while (c != EOF && c_isspace(c)) {
+ c= getchar();
+ if (c == EOF)
+ ohshit(_("unexpected end of file after package name at line %d"), lno);
+ if (c == '\n') ohshit(_("unexpected end of line after package name at line %d"),lno);
+ }
+
+ varbuf_reset(&selvb);
+ while (c != EOF && !c_isspace(c)) {
+ varbuf_add_char(&selvb, c);
+ c= getchar();
+ }
+ varbuf_end_str(&selvb);
+
+ while (c != EOF && c != '\n') {
+ c= getchar();
+ if (!c_isspace(c))
+ ohshit(_("unexpected data after package and selection at line %d"),lno);
+ }
+ pkg = pkg_spec_parse_pkg(namevb.buf, &err);
+ if (pkg == NULL)
+ ohshit(_("illegal package name at line %d: %.250s"), lno, err.str);
+
+ if (!pkg_is_informative(pkg, &pkg->installed) &&
+ !pkg_is_informative(pkg, &pkg->available)) {
+ db_possibly_outdated = true;
+ warning(_("package not in status nor available database at line %d: %.250s"), lno, namevb.buf);
+ lno++;
+ continue;
+ }
+
+ nv = namevalue_find_by_name(wantinfos, selvb.buf);
+ if (nv == NULL)
+ ohshit(_("unknown wanted status at line %d: %.250s"), lno, selvb.buf);
+
+ pkg_set_want(pkg, nv->value);
+ if (c == EOF) break;
+ lno++;
+ }
+ if (ferror(stdin)) ohshite(_("read error on standard input"));
+ modstatdb_shutdown();
+ varbuf_destroy(&namevb);
+ varbuf_destroy(&selvb);
+
+ if (db_possibly_outdated)
+ warning(_("found unknown packages; this might mean the available database\n"
+ "is outdated, and needs to be updated through a frontend method;\n"
+ "please see the FAQ <https://wiki.debian.org/Teams/Dpkg/FAQ#set-selections>"));
+
+ return 0;
+}
+
+int
+clearselections(const char *const *argv)
+{
+ enum modstatdb_rw msdbflags;
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ if (f_noact)
+ msdbflags = msdbrw_readonly;
+ else
+ msdbflags = msdbrw_write;
+
+ modstatdb_open(msdbflags);
+ pkg_infodb_upgrade();
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (!pkg->installed.essential &&
+ !pkg->installed.is_protected &&
+ pkg->want != PKG_WANT_UNKNOWN)
+ pkg_set_want(pkg, PKG_WANT_DEINSTALL);
+ }
+ pkg_hash_iter_free(iter);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
diff --git a/src/main/trigproc.c b/src/main/trigproc.c
new file mode 100644
index 0000000..2ef8a52
--- /dev/null
+++ b/src/main/trigproc.c
@@ -0,0 +1,576 @@
+/*
+ * dpkg - main program for package management
+ * trigproc.c - trigger processing
+ *
+ * Copyright © 2007 Canonical Ltd
+ * written by 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 <sys/stat.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/pkg.h>
+#include <dpkg/pkg-queue.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+#include <dpkg/triglib.h>
+
+#include "main.h"
+
+/*
+ * Trigger processing algorithms:
+ *
+ *
+ * There is a separate queue (‘deferred trigproc list’) for triggers
+ * ‘relevant’ to what we just did; when we find something triggered ‘now’
+ * we add it to that queue (unless --no-triggers).
+ *
+ *
+ * We want to prefer configuring packages where possible to doing trigger
+ * processing, although it would be better to prefer trigger processing
+ * to cycle-breaking we need to do the latter first or we might generate
+ * artificial trigger cycles, but we always want to prefer trigger
+ * processing to dependency forcing. This is achieved as follows:
+ *
+ * Each time during configure processing where a package D is blocked by
+ * only (ie Depends unsatisfied but would be satisfied by) a t-awaiter W
+ * we make a note of (one of) W's t-pending, T. (Only the last such T.)
+ * (If --no-triggers and nonempty argument list and package isn't in
+ * argument list then we don't do this.)
+ *
+ * Each time in process_queue() where we increment dependtry, we instead
+ * see if we have encountered such a t-pending T. If we do and are in
+ * a trigger processing try, we trigproc T instead of incrementing
+ * dependtry and this counts as having done something so we reset
+ * sincenothing.
+ *
+ *
+ * For --triggers-only and --configure, we go through each thing in the
+ * argument queue (the enqueue_package queue) and check what its state is
+ * and if appropriate we trigproc it. If we didn't have a queue (or had
+ * just --pending) we search all triggers-pending packages and add them
+ * to the deferred trigproc list.
+ *
+ *
+ * Before quitting from most operations, we trigproc each package in the
+ * deferred trigproc list. This may (if not --no-triggers) of course add
+ * new things to the deferred trigproc list.
+ *
+ *
+ * Note that ‘we trigproc T’ must involve trigger cycle detection and
+ * also automatic setting of t-awaiters to t-pending or installed. In
+ * particular, we do cycle detection even for trigger processing in the
+ * configure dependtry loop (and it is OK to do it for explicitly
+ * specified packages from the command line arguments; duplicates are
+ * removed by packages.c:process_queue).
+ */
+
+/*========== Deferred trigger queue. ==========*/
+
+static struct pkg_queue deferred = PKG_QUEUE_INIT;
+
+static void
+trigproc_enqueue_deferred(struct pkginfo *pend)
+{
+ if (f_triggers < 0)
+ return;
+ ensure_package_clientdata(pend);
+ if (pend->clientdata->trigprocdeferred)
+ return;
+ pend->clientdata->trigprocdeferred = pkg_queue_push(&deferred, pend);
+ debug(dbg_triggers, "trigproc_enqueue_deferred pend=%s",
+ pkg_name(pend, pnaw_always));
+}
+
+/**
+ * Populate the deferred trigger queue.
+ *
+ * When dpkg is called with a specific set of packages to act on, we might
+ * have packages pending trigger processing. But because there are frontends
+ * that do not perform a final «dpkg --configure --pending» call (i.e. apt),
+ * the system is left in a state with packages not fully installed.
+ *
+ * We have to populate the deferred trigger queue from the entire package
+ * database, so that we might try to do opportunistic trigger processing
+ * when going through the deferred trigger queue, because a fixed apt will
+ * not request the necessary processing anyway.
+ *
+ * XXX: This can be removed once apt is fixed in the next stable release.
+ */
+void
+trigproc_populate_deferred(void)
+{
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (!pkg->trigpend_head)
+ continue;
+
+ if (pkg->status != PKG_STAT_TRIGGERSAWAITED &&
+ pkg->status != PKG_STAT_TRIGGERSPENDING)
+ continue;
+
+ if (pkg->want != PKG_WANT_INSTALL &&
+ pkg->want != PKG_WANT_HOLD)
+ continue;
+
+ trigproc_enqueue_deferred(pkg);
+ }
+ pkg_hash_iter_free(iter);
+}
+
+void
+trigproc_run_deferred(void)
+{
+ jmp_buf ejbuf;
+
+ debug(dbg_triggers, "trigproc_run_deferred");
+ while (!pkg_queue_is_empty(&deferred)) {
+ struct pkginfo *pkg;
+
+ pkg = pkg_queue_pop(&deferred);
+ if (!pkg)
+ continue;
+
+ if (setjmp(ejbuf)) {
+ pop_error_context(ehflag_bombout);
+ continue;
+ }
+ push_error_context_jump(&ejbuf, print_error_perpackage,
+ pkg_name(pkg, pnaw_nonambig));
+
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->trigprocdeferred = NULL;
+ trigproc(pkg, TRIGPROC_TRY_DEFERRED);
+
+ pop_error_context(ehflag_normaltidy);
+ }
+}
+
+/*
+ * Called by modstatdb_note.
+ */
+void
+trig_activate_packageprocessing(struct pkginfo *pkg)
+{
+ debug(dbg_triggersdetail, "trigproc_activate_packageprocessing pkg=%s",
+ pkg_name(pkg, pnaw_always));
+
+ trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed, TRIGGERSCIFILE),
+ NULL, trig_cicb_statuschange_activate,
+ pkg, &pkg->installed);
+}
+
+/*========== Actual trigger processing. ==========*/
+
+struct trigcyclenode {
+ struct trigcyclenode *next;
+ struct trigcycleperpkg *pkgs;
+ struct pkginfo *then_processed;
+};
+
+struct trigcycleperpkg {
+ struct trigcycleperpkg *next;
+ struct pkginfo *pkg;
+ struct trigpend *then_trigs;
+};
+
+static bool tortoise_advance;
+static struct trigcyclenode *tortoise, *hare;
+
+void
+trigproc_reset_cycle(void)
+{
+ tortoise_advance = false;
+ tortoise = hare = NULL;
+}
+
+static bool
+tortoise_in_hare(struct pkginfo *processing_now,
+ struct trigcycleperpkg *tortoise_pkg)
+{
+ const char *processing_now_name, *tortoise_name;
+ struct trigpend *hare_trig, *tortoise_trig;
+
+ processing_now_name = pkg_name(processing_now, pnaw_nonambig);
+ tortoise_name = pkg_name(tortoise_pkg->pkg, pnaw_nonambig);
+
+ debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s", __func__,
+ processing_now_name, tortoise_name);
+ for (tortoise_trig = tortoise_pkg->then_trigs;
+ tortoise_trig;
+ tortoise_trig = tortoise_trig->next) {
+ debug(dbg_triggersdetail,
+ "%s pnow=%s tortoise=%s tortoisetrig=%s", __func__,
+ processing_now_name, tortoise_name, tortoise_trig->name);
+
+ /* hare is now so we can just look up in the actual data. */
+ for (hare_trig = tortoise_pkg->pkg->trigpend_head;
+ hare_trig;
+ hare_trig = hare_trig->next) {
+ debug(dbg_triggersstupid, "%s pnow=%s tortoise=%s"
+ " tortoisetrig=%s haretrig=%s", __func__,
+ processing_now_name, tortoise_name,
+ tortoise_trig->name, hare_trig->name);
+ if (strcmp(hare_trig->name, tortoise_trig->name) == 0)
+ break;
+ }
+
+ if (hare_trig == NULL) {
+ /* Not found in hare, yay! */
+ debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s OK",
+ __func__, processing_now_name, tortoise_name);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static struct trigcyclenode *
+trigproc_new_cyclenode(struct pkginfo *processing_now)
+{
+ struct trigcyclenode *tcn;
+ struct trigcycleperpkg *tcpp;
+ struct pkginfo *pkg;
+ struct pkg_hash_iter *iter;
+
+ tcn = nfmalloc(sizeof(*tcn));
+ tcn->pkgs = NULL;
+ tcn->next = NULL;
+ tcn->then_processed = processing_now;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (!pkg->trigpend_head)
+ continue;
+ tcpp = nfmalloc(sizeof(*tcpp));
+ tcpp->pkg = pkg;
+ tcpp->then_trigs = pkg->trigpend_head;
+ tcpp->next = tcn->pkgs;
+ tcn->pkgs = tcpp;
+ }
+ pkg_hash_iter_free(iter);
+
+ return tcn;
+}
+
+/*
+ * Returns package we are to give up on.
+ */
+static struct pkginfo *
+check_trigger_cycle(struct pkginfo *processing_now)
+{
+ struct trigcyclenode *tcn;
+ struct trigcycleperpkg *tortoise_pkg;
+ struct trigpend *tortoise_trig;
+ struct pkginfo *giveup;
+ const char *sep;
+
+ debug(dbg_triggers, "check_triggers_cycle pnow=%s",
+ pkg_name(processing_now, pnaw_always));
+
+ tcn = trigproc_new_cyclenode(processing_now);
+
+ if (!hare) {
+ debug(dbg_triggersdetail, "check_triggers_cycle pnow=%s first",
+ pkg_name(processing_now, pnaw_always));
+ hare = tortoise = tcn;
+ return NULL;
+ }
+
+ hare->next = tcn;
+ hare = hare->next;
+ if (tortoise_advance)
+ tortoise = tortoise->next;
+ tortoise_advance = !tortoise_advance;
+
+ /* Now we compare hare to tortoise.
+ * We want to find a trigger pending in tortoise which is not in hare
+ * if we find such a thing we have proved that hare isn't a superset
+ * of tortoise and so that we haven't found a loop (yet). */
+ for (tortoise_pkg = tortoise->pkgs;
+ tortoise_pkg;
+ tortoise_pkg = tortoise_pkg->next) {
+ if (!tortoise_in_hare(processing_now, tortoise_pkg))
+ return NULL;
+ }
+ /* Oh dear. hare is a superset of tortoise. We are making no
+ * progress. */
+ notice(_("cycle found while processing triggers:\n"
+ " chain of packages whose triggers are or may be responsible:"));
+ sep = " ";
+ for (tcn = tortoise; tcn; tcn = tcn->next) {
+ fprintf(stderr, "%s%s", sep,
+ pkg_name(tcn->then_processed, pnaw_nonambig));
+ sep = " -> ";
+ }
+ fprintf(stderr, _("\n" " packages' pending triggers which are"
+ " or may be unresolvable:\n"));
+ for (tortoise_pkg = tortoise->pkgs;
+ tortoise_pkg;
+ tortoise_pkg = tortoise_pkg->next) {
+ fprintf(stderr, " %s",
+ pkg_name(tortoise_pkg->pkg, pnaw_nonambig));
+ sep = ": ";
+ for (tortoise_trig = tortoise_pkg->then_trigs;
+ tortoise_trig;
+ tortoise_trig = tortoise_trig->next) {
+ fprintf(stderr, "%s%s", sep, tortoise_trig->name);
+ }
+ fprintf(stderr, "\n");
+ }
+
+ /* We give up on the _earliest_ package involved. */
+ giveup = tortoise->pkgs->pkg;
+ debug(dbg_triggers, "check_triggers_cycle pnow=%s giveup=%s",
+ pkg_name(processing_now, pnaw_always),
+ pkg_name(giveup, pnaw_always));
+ if (giveup->status != PKG_STAT_TRIGGERSAWAITED &&
+ giveup->status != PKG_STAT_TRIGGERSPENDING)
+ internerr("package %s in non-trigger state %s",
+ pkg_name(giveup, pnaw_always),
+ pkg_status_name(giveup));
+ giveup->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ pkg_set_status(giveup, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(giveup);
+ print_error_perpackage(_("triggers looping, abandoned"),
+ pkg_name(giveup, pnaw_nonambig));
+
+ return giveup;
+}
+
+/*
+ * Does cycle checking. Doesn't mind if pkg has no triggers pending - in
+ * that case does nothing but fix up any stale awaiters.
+ */
+void
+trigproc(struct pkginfo *pkg, enum trigproc_type type)
+{
+ static struct varbuf namesarg;
+
+ struct varbuf depwhynot = VARBUF_INIT;
+ struct trigpend *tp;
+ struct pkginfo *gaveup;
+
+ debug(dbg_triggers, "trigproc %s", pkg_name(pkg, pnaw_always));
+
+ ensure_package_clientdata(pkg);
+ if (pkg->clientdata->trigprocdeferred)
+ pkg->clientdata->trigprocdeferred->pkg = NULL;
+ pkg->clientdata->trigprocdeferred = NULL;
+
+ if (pkg->trigpend_head) {
+ enum dep_check ok;
+
+ if (pkg->status != PKG_STAT_TRIGGERSPENDING &&
+ pkg->status != PKG_STAT_TRIGGERSAWAITED)
+ internerr("package %s in non-trigger state %s",
+ pkg_name(pkg, pnaw_always),
+ pkg_status_name(pkg));
+
+ if (dependtry < DEPEND_TRY_TRIGGERS &&
+ type == TRIGPROC_TRY_QUEUED) {
+ /* We are not yet in a triggers run, so postpone this
+ * package completely. */
+ enqueue_package(pkg);
+ return;
+ }
+
+ if (dependtry >= DEPEND_TRY_CYCLES) {
+ if (findbreakcycle(pkg))
+ sincenothing = 0;
+ }
+
+ ok = dependencies_ok(pkg, NULL, &depwhynot);
+ if (ok == DEP_CHECK_DEFER) {
+ if (dependtry >= DEPEND_TRY_TRIGGERS_CYCLES) {
+ gaveup = check_trigger_cycle(pkg);
+ if (gaveup == pkg)
+ return;
+ }
+
+ varbuf_destroy(&depwhynot);
+ enqueue_package(pkg);
+ return;
+ } else if (ok == DEP_CHECK_HALT) {
+ /* When doing opportunistic deferred trigger processing,
+ * nothing requires us to be able to make progress;
+ * skip the package and silently ignore the error due
+ * to unsatisfiable dependencies. And because we can
+ * end up here repeatedly, if this package is required
+ * to make progress for other packages, we need to
+ * reset the trigger cycle tracking to avoid detecting
+ * bogus cycles*/
+ if (type == TRIGPROC_TRY_DEFERRED) {
+ trigproc_reset_cycle();
+
+ varbuf_destroy(&depwhynot);
+ return;
+ }
+
+ sincenothing = 0;
+ varbuf_end_str(&depwhynot);
+ notice(_("dependency problems prevent processing "
+ "triggers for %s:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), depwhynot.buf);
+ varbuf_destroy(&depwhynot);
+ ohshit(_("dependency problems - leaving triggers unprocessed"));
+ } else if (depwhynot.used) {
+ varbuf_end_str(&depwhynot);
+ notice(_("%s: dependency problems, but processing "
+ "triggers anyway as you requested:\n%s"),
+ pkg_name(pkg, pnaw_nonambig), depwhynot.buf);
+ varbuf_destroy(&depwhynot);
+ }
+
+ gaveup = check_trigger_cycle(pkg);
+ if (gaveup == pkg)
+ return;
+
+ printf(_("Processing triggers for %s (%s) ...\n"),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ log_action("trigproc", pkg, &pkg->installed);
+
+ varbuf_reset(&namesarg);
+ for (tp = pkg->trigpend_head; tp; tp = tp->next) {
+ varbuf_add_char(&namesarg, ' ');
+ varbuf_add_str(&namesarg, tp->name);
+ }
+ varbuf_end_str(&namesarg);
+
+ /* Setting the status to half-configured
+ * causes modstatdb_note to clear pending triggers. */
+ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(pkg);
+
+ if (!f_noact) {
+ sincenothing = 0;
+ maintscript_postinst(pkg, "triggered",
+ namesarg.buf + 1, NULL);
+ }
+
+ post_postinst_tasks(pkg, PKG_STAT_INSTALLED);
+ } else {
+ /* In other branch is done by modstatdb_note(), from inside
+ * post_postinst_tasks(). */
+ trig_clear_awaiters(pkg);
+ }
+}
+
+/*========== Transitional global activation. ==========*/
+
+static void
+transitional_interest_callback_ro(const char *trig, struct pkginfo *pkg,
+ struct pkgbin *pkgbin, enum trig_options opts)
+{
+ struct pkginfo *pend = pkg;
+ struct pkgbin *pendbin = pkgbin;
+
+ debug(dbg_triggersdetail,
+ "trig_transitional_interest_callback trig=%s pend=%s",
+ trig, pkgbin_name(pend, pendbin, pnaw_always));
+ if (pend->status >= PKG_STAT_TRIGGERSAWAITED)
+ trig_note_pend(pend, nfstrsave(trig));
+}
+
+static void
+transitional_interest_callback(const char *trig, struct pkginfo *pkg,
+ struct pkgbin *pkgbin, enum trig_options opts)
+{
+ struct pkginfo *pend = pkg;
+ struct pkgbin *pendbin = pkgbin;
+
+ trig_cicb_interest_add(trig, pend, pendbin, opts);
+ transitional_interest_callback_ro(trig, pend, pendbin, opts);
+}
+
+/*
+ * cstatus might be msdbrw_readonly if we're in --no-act mode, in which
+ * case we don't write out all of the interest files etc. but we do
+ * invent all of the activations for our own benefit.
+ */
+static void
+trig_transitional_activate(enum modstatdb_rw cstatus)
+{
+ struct pkg_hash_iter *iter;
+ struct pkginfo *pkg;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter))) {
+ if (pkg->status <= PKG_STAT_HALFINSTALLED)
+ continue;
+ debug(dbg_triggersdetail, "trig_transitional_activate %s %s",
+ pkg_name(pkg, pnaw_always),
+ pkg_status_name(pkg));
+ pkg->trigpend_head = NULL;
+ trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed,
+ TRIGGERSCIFILE),
+ cstatus >= msdbrw_write ?
+ transitional_interest_callback :
+ transitional_interest_callback_ro, NULL,
+ pkg, &pkg->installed);
+ /* Ensure we're not creating incoherent data that can't
+ * be written down. This should never happen in theory but
+ * can happen if you restore an old status file that is
+ * not in sync with the infodb files. */
+ if (pkg->status < PKG_STAT_TRIGGERSAWAITED)
+ continue;
+
+ if (pkg->trigaw.head)
+ pkg_set_status(pkg, PKG_STAT_TRIGGERSAWAITED);
+ else if (pkg->trigpend_head)
+ pkg_set_status(pkg, PKG_STAT_TRIGGERSPENDING);
+ else
+ pkg_set_status(pkg, PKG_STAT_INSTALLED);
+ }
+ pkg_hash_iter_free(iter);
+
+ if (cstatus >= msdbrw_write) {
+ modstatdb_checkpoint();
+ trig_file_interests_save();
+ }
+}
+
+/*========== Hook setup. ==========*/
+
+TRIGHOOKS_DEFINE_NAMENODE_ACCESSORS
+
+static const struct trig_hooks trig_our_hooks = {
+ .enqueue_deferred = trigproc_enqueue_deferred,
+ .transitional_activate = trig_transitional_activate,
+ .namenode_find = th_nn_find,
+ .namenode_interested = th_nn_interested,
+ .namenode_name = th_nn_name,
+};
+
+void
+trigproc_install_hooks(void)
+{
+ trig_override_hooks(&trig_our_hooks);
+}
diff --git a/src/main/unpack.c b/src/main/unpack.c
new file mode 100644
index 0000000..98d272f
--- /dev/null
+++ b/src/main/unpack.c
@@ -0,0 +1,1733 @@
+/*
+ * dpkg - main program for package management
+ * unpack.c - .deb archive unpacking
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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 <string.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdint.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/pkg.h>
+#include <dpkg/pkg-queue.h>
+#include <dpkg/path.h>
+#include <dpkg/buffer.h>
+#include <dpkg/subproc.h>
+#include <dpkg/dir.h>
+#include <dpkg/tarfn.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+#include <dpkg/triglib.h>
+
+#include "file-match.h"
+#include "main.h"
+#include "archives.h"
+
+static const char *
+summarize_filename(const char *filename)
+{
+ const char *pfilename;
+ char *pfilenamebuf;
+
+ for (pfilename = filename;
+ pfilename && strlen(pfilename) > 30 && strchr(pfilename, '/') != NULL;
+ pfilename++)
+ pfilename = strchr(pfilename, '/');
+
+ if (pfilename && pfilename != filename) {
+ pfilenamebuf = nfmalloc(strlen(pfilename) + 5);
+ sprintf(pfilenamebuf, _(".../%s"), pfilename);
+ pfilename = pfilenamebuf;
+ } else {
+ pfilename = filename;
+ }
+
+ return pfilename;
+}
+
+static bool
+deb_reassemble(const char **filename, const char **pfilename)
+{
+ static char *reasmbuf = NULL;
+ struct stat stab;
+ int status;
+ pid_t pid;
+
+ if (!reasmbuf)
+ reasmbuf = dpkg_db_get_path(REASSEMBLETMP);
+ if (unlink(reasmbuf) && errno != ENOENT)
+ ohshite(_("error ensuring '%.250s' doesn't exist"), reasmbuf);
+
+ push_cleanup(cu_pathname, ~0, 1, (void *)reasmbuf);
+
+ pid = subproc_fork();
+ if (!pid) {
+ execlp(SPLITTER, SPLITTER, "-Qao", reasmbuf, *filename, NULL);
+ ohshite(_("unable to execute %s (%s)"),
+ _("split package reassembly"), SPLITTER);
+ }
+ status = subproc_reap(pid, SPLITTER, SUBPROC_RETERROR);
+ switch (status) {
+ case 0:
+ /* It was a part - is it complete? */
+ if (!stat(reasmbuf, &stab)) {
+ /* Yes. */
+ *filename = reasmbuf;
+ *pfilename = _("reassembled package file");
+ break;
+ } else if (errno == ENOENT) {
+ /* No. That's it, we skip it. */
+ return false;
+ }
+ case 1:
+ /* No, it wasn't a part. */
+ break;
+ default:
+ ohshit(_("subprocess %s returned error exit status %d"), SPLITTER, status);
+ }
+
+ return true;
+}
+
+static void
+deb_verify(const char *filename)
+{
+ pid_t pid;
+
+ /* We have to check on every unpack, in case the debsig-verify package
+ * gets installed or removed. */
+ if (!find_command(DEBSIGVERIFY))
+ return;
+
+ printf(_("Authenticating %s ...\n"), filename);
+ fflush(stdout);
+ pid = subproc_fork();
+ if (!pid) {
+ execlp(DEBSIGVERIFY, DEBSIGVERIFY, "-q", filename, NULL);
+ ohshite(_("unable to execute %s (%s)"),
+ _("package signature verification"), DEBSIGVERIFY);
+ } else {
+ int status;
+
+ status = subproc_reap(pid, "debsig-verify", SUBPROC_NOCHECK);
+ if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ if (!in_force(FORCE_BAD_VERIFY))
+ ohshit(_("verification on package %s failed!"), filename);
+ else
+ notice(_("verification on package %s failed; "
+ "but installing anyway as you requested"), filename);
+ } else {
+ printf(_("passed\n"));
+ }
+ }
+}
+
+static char *
+get_control_dir(char *cidir)
+{
+ if (f_noact) {
+ char *tmpdir;
+
+ tmpdir = mkdtemp(path_make_temp_template("dpkg"));
+ if (tmpdir == NULL)
+ ohshite(_("unable to create temporary directory"));
+
+ cidir = m_realloc(cidir, strlen(tmpdir) + MAXCONTROLFILENAME + 10);
+
+ strcpy(cidir, tmpdir);
+
+ free(tmpdir);
+ } else {
+ const char *admindir;
+
+ admindir = dpkg_db_get_dir();
+
+ /* The admindir length is always constant on a dpkg execution run. */
+ if (cidir == NULL)
+ cidir = m_malloc(strlen(admindir) + sizeof(CONTROLDIRTMP) +
+ MAXCONTROLFILENAME + 10);
+
+ /* We want it to be on the same filesystem so that we can
+ * use rename(2) to install the postinst &c. */
+ strcpy(cidir, admindir);
+ strcat(cidir, "/" CONTROLDIRTMP);
+
+ /* Make sure the control information directory is empty. */
+ path_remove_tree(cidir);
+ }
+
+ strcat(cidir, "/");
+
+ return cidir;
+}
+
+static void
+pkg_check_depcon(struct pkginfo *pkg, const char *pfilename)
+{
+ struct dependency *dsearch;
+ struct deppossi *psearch;
+ struct pkginfo *fixbytrigaw;
+ static struct varbuf depprobwhy;
+
+ /* Check if anything is installed that we conflict with, or not installed
+ * that we need. */
+ ensure_package_clientdata(pkg);
+ pkg->clientdata->istobe = PKG_ISTOBE_INSTALLNEW;
+
+ for (dsearch = pkg->available.depends; dsearch; dsearch = dsearch->next) {
+ switch (dsearch->type) {
+ case dep_conflicts:
+ /* Look for things we conflict with. */
+ check_conflict(dsearch, pkg, pfilename);
+ break;
+ case dep_breaks:
+ /* Look for things we break. */
+ check_breaks(dsearch, pkg, pfilename);
+ break;
+ case dep_provides:
+ /* Look for things that conflict with what we provide. */
+ for (psearch = dsearch->list->ed->depended.installed;
+ psearch;
+ psearch = psearch->rev_next) {
+ if (psearch->up->type != dep_conflicts)
+ continue;
+ check_conflict(psearch->up, pkg, pfilename);
+ }
+ break;
+ case dep_suggests:
+ case dep_recommends:
+ case dep_depends:
+ case dep_replaces:
+ case dep_enhances:
+ /* Ignore these here. */
+ break;
+ case dep_predepends:
+ if (!depisok(dsearch, &depprobwhy, NULL, &fixbytrigaw, true)) {
+ if (fixbytrigaw) {
+ while (fixbytrigaw->trigaw.head)
+ trigproc(fixbytrigaw->trigaw.head->pend, TRIGPROC_REQUIRED);
+ } else {
+ varbuf_end_str(&depprobwhy);
+ notice(_("regarding %s containing %s, pre-dependency problem:\n%s"),
+ pfilename, pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ depprobwhy.buf);
+ if (!force_depends(dsearch->list))
+ ohshit(_("pre-dependency problem - not installing %.250s"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ warning(_("ignoring pre-dependency problem!"));
+ }
+ }
+ }
+ }
+
+ /* Look for things that conflict with us. */
+ for (psearch = pkg->set->depended.installed; psearch; psearch = psearch->rev_next) {
+ if (psearch->up->type != dep_conflicts)
+ continue;
+
+ check_conflict(psearch->up, pkg, pfilename);
+ }
+}
+
+static void
+pkg_deconfigure_others(struct pkginfo *pkg)
+{
+ struct pkg_deconf_list *deconpil;
+
+ for (deconpil = deconfigure; deconpil; deconpil = deconpil->next) {
+ struct pkginfo *removing = deconpil->pkg_removal;
+
+ if (deconpil->reason == PKG_WANT_DEINSTALL) {
+ printf(_("De-configuring %s (%s), to allow removal of %s (%s) ...\n"),
+ pkg_name(deconpil->pkg, pnaw_nonambig),
+ versiondescribe(&deconpil->pkg->installed.version, vdew_nonambig),
+ pkg_name(removing, pnaw_nonambig),
+ versiondescribe(&removing->installed.version, vdew_nonambig));
+ } else if (deconpil->reason == PKG_WANT_INSTALL) {
+ printf(_("De-configuring %s (%s), to allow installation of %s (%s) ...\n"),
+ pkg_name(deconpil->pkg, pnaw_nonambig),
+ versiondescribe(&deconpil->pkg->installed.version, vdew_nonambig),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig));
+ } else {
+ printf(_("De-configuring %s (%s), to allow configuration of %s (%s) ...\n"),
+ pkg_name(deconpil->pkg, pnaw_nonambig),
+ versiondescribe(&deconpil->pkg->installed.version, vdew_nonambig),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig));
+ }
+
+ trig_activate_packageprocessing(deconpil->pkg);
+ pkg_set_status(deconpil->pkg, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(deconpil->pkg);
+
+ /* This means that we *either* go and run postinst abort-deconfigure,
+ * *or* queue the package for later configure processing, depending
+ * on which error cleanup route gets taken. */
+ push_cleanup_fallback(cu_prermdeconfigure, ~ehflag_normaltidy,
+ ok_prermdeconfigure, ehflag_normaltidy,
+ 3, (void *)deconpil->pkg, (void *)removing, (void *)pkg);
+
+ if (removing) {
+ maintscript_installed(deconpil->pkg, PRERMFILE, "pre-removal",
+ "deconfigure", "in-favour",
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ versiondescribe(&pkg->available.version,
+ vdew_nonambig),
+ "removing",
+ pkg_name(removing, pnaw_nonambig),
+ versiondescribe(&removing->installed.version,
+ vdew_nonambig),
+ NULL);
+ } else {
+ maintscript_installed(deconpil->pkg, PRERMFILE, "pre-removal",
+ "deconfigure", "in-favour",
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ versiondescribe(&pkg->available.version,
+ vdew_nonambig),
+ NULL);
+ }
+ }
+}
+
+/**
+ * Read the conffiles, and copy the hashes across.
+ */
+static void
+deb_parse_conffiles(const struct pkginfo *pkg, const char *control_conffiles,
+ struct fsys_namenode_queue *newconffiles)
+{
+ FILE *conff;
+ char conffilenamebuf[MAXCONFFILENAME];
+
+ conff = fopen(control_conffiles, "r");
+ if (conff == NULL) {
+ if (errno == ENOENT)
+ return;
+ ohshite(_("error trying to open %.250s"), control_conffiles);
+ }
+
+ push_cleanup(cu_closestream, ehflag_bombout, 1, conff);
+
+ while (fgets(conffilenamebuf, MAXCONFFILENAME - 2, conff)) {
+ struct pkginfo *otherpkg;
+ struct fsys_node_pkgs_iter *iter;
+ struct fsys_namenode *namenode;
+ struct fsys_namenode_list *newconff;
+ struct conffile *searchconff;
+ char *conffilename = conffilenamebuf;
+ char *p;
+ enum fsys_namenode_flags confflags = FNNF_NEW_CONFF;
+
+ p = conffilename + strlen(conffilename);
+ if (p == conffilename)
+ ohshit(_("conffile file contains an empty line"));
+ if (p[-1] != '\n')
+ ohshit(_("conffile name '%s' is too long, or missing final newline"),
+ conffilename);
+ p = str_rtrim_spaces(conffilename, p);
+ if (p == conffilename)
+ continue;
+
+ /* Check for conffile flags. */
+ if (conffilename[0] != '/') {
+ char *flag = conffilename;
+ char *flag_end = strchr(flag, ' ');
+
+ if (flag_end)
+ conffilename = flag_end + 1;
+
+ /* If no flag separator is found, assume a missing leading slash. */
+ if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
+ ohshit(_("conffile name '%s' is not an absolute pathname"), conffilename);
+
+ flag_end[0] = '\0';
+
+ /* Otherwise assume a missing filename after the flag separator. */
+ if (conffilename[0] == '\0')
+ ohshit(_("conffile name missing after flag '%s'"), flag);
+
+ if (strcmp(flag, "remove-on-upgrade") == 0) {
+ confflags |= FNNF_RM_CONFF_ON_UPGRADE;
+ confflags &= ~FNNF_NEW_CONFF;
+ } else {
+ if (c_isspace(flag[0]))
+ warning(_("line with conffile filename '%s' has leading white spaces"),
+ conffilename);
+ ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
+ }
+ }
+
+ namenode = fsys_hash_find_node(conffilename, 0);
+ namenode->oldhash = NEWCONFFILEFLAG;
+ newconff = tar_fsys_namenode_queue_push(newconffiles, namenode);
+
+ /*
+ * Let's see if any packages have this file.
+ *
+ * If they do we check to see if they listed it as a conffile,
+ * and if they did we copy the hash across. Since (for plain
+ * file conffiles, which is the only kind we are supposed to
+ * have) there will only be one package which ‘has’ the file,
+ * this will usually mean we only look in the package which
+ * we are installing now.
+ *
+ * The ‘conffiles’ data in the status file is ignored when a
+ * package is not also listed in the file ownership database as
+ * having that file. If several packages are listed as owning
+ * the file we pick one at random.
+ */
+ searchconff = NULL;
+
+ iter = fsys_node_pkgs_iter_new(newconff->namenode);
+ while ((otherpkg = fsys_node_pkgs_iter_next(iter))) {
+ debug(dbg_conffdetail,
+ "process_archive conffile '%s' in package %s - conff ?",
+ newconff->namenode->name, pkg_name(otherpkg, pnaw_always));
+ for (searchconff = otherpkg->installed.conffiles;
+ searchconff && strcmp(newconff->namenode->name, searchconff->name);
+ searchconff = searchconff->next)
+ debug(dbg_conffdetail,
+ "process_archive conffile '%s' in package %s - conff ? not '%s'",
+ newconff->namenode->name, pkg_name(otherpkg, pnaw_always),
+ searchconff->name);
+ if (searchconff) {
+ debug(dbg_conff,
+ "process_archive conffile '%s' package=%s %s hash=%s",
+ newconff->namenode->name, pkg_name(otherpkg, pnaw_always),
+ otherpkg == pkg ? "same" : "different!",
+ searchconff->hash);
+ if (otherpkg == pkg)
+ break;
+ }
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ if (searchconff) {
+ /* We don't copy ‘obsolete’; it's not obsolete in the new package. */
+ newconff->namenode->oldhash = searchconff->hash;
+ } else {
+ debug(dbg_conff, "process_archive conffile '%s' no package, no hash",
+ newconff->namenode->name);
+ }
+ newconff->namenode->flags |= confflags;
+ }
+
+ if (ferror(conff))
+ ohshite(_("read error in %.250s"), control_conffiles);
+ pop_cleanup(ehflag_normaltidy); /* conff = fopen() */
+ if (fclose(conff))
+ ohshite(_("error closing %.250s"), control_conffiles);
+}
+
+static struct pkg_queue conflictors = PKG_QUEUE_INIT;
+
+void
+enqueue_conflictor(struct pkginfo *pkg)
+{
+ pkg_queue_push(&conflictors, pkg);
+}
+
+static void
+pkg_infodb_remove_file(const char *filename, const char *filetype)
+{
+ if (unlink(filename))
+ ohshite(_("unable to delete control info file '%.250s'"), filename);
+
+ debug(dbg_scripts, "removal_bulk info unlinked %s", filename);
+}
+
+static struct match_node *match_head = NULL;
+
+static void
+pkg_infodb_update_file(const char *filename, const char *filetype)
+{
+ if (strlen(filetype) > MAXCONTROLFILENAME)
+ ohshit(_("old version of package has overly-long info file name starting '%.250s'"),
+ filename);
+
+ /* We do the list separately. */
+ if (strcmp(filetype, LISTFILE) == 0)
+ return;
+
+ /* We keep files to rename in a list as doing the rename immediately
+ * might influence the current readdir(), the just renamed file might
+ * be returned a second time as it's actually a new file from the
+ * point of view of the filesystem. */
+ match_head = match_node_new(filename, filetype, match_head);
+}
+
+static void
+pkg_infodb_update(struct pkginfo *pkg, char *cidir, char *cidirrest)
+{
+ struct match_node *match_node;
+ DIR *dsd;
+ struct dirent *de;
+
+ /* Deallocate the match list in case we aborted previously. */
+ while ((match_node = match_head)) {
+ match_head = match_node->next;
+ match_node_free(match_node);
+ }
+
+ pkg_infodb_foreach(pkg, &pkg->available, pkg_infodb_update_file);
+
+ while ((match_node = match_head)) {
+ strcpy(cidirrest, match_node->filetype);
+
+ if (!rename(cidir, match_node->filename)) {
+ debug(dbg_scripts, "process_archive info installed %s as %s",
+ cidir, match_node->filename);
+ } else if (errno == ENOENT) {
+ /* Right, no new version. */
+ if (unlink(match_node->filename))
+ ohshite(_("unable to remove obsolete info file '%.250s'"),
+ match_node->filename);
+ debug(dbg_scripts, "process_archive info unlinked %s",
+ match_node->filename);
+ } else {
+ ohshite(_("unable to install (supposed) new info file '%.250s'"), cidir);
+ }
+ match_head = match_node->next;
+ match_node_free(match_node);
+ }
+
+ /* The control directory itself. */
+ cidirrest[0] = '\0';
+ dsd = opendir(cidir);
+ if (!dsd)
+ ohshite(_("unable to open temp control directory"));
+ push_cleanup(cu_closedir, ~0, 1, (void *)dsd);
+ while ((de = readdir(dsd))) {
+ const char *newinfofilename;
+
+ if (strchr(de->d_name, '.')) {
+ debug(dbg_scripts, "process_archive tmp.ci script/file '%s' contains dot",
+ de->d_name);
+ continue;
+ }
+ if (strlen(de->d_name) > MAXCONTROLFILENAME)
+ ohshit(_("package contains overly-long control info file name (starting '%.50s')"),
+ de->d_name);
+
+ strcpy(cidirrest, de->d_name);
+
+ /* First we check it's not a directory. */
+ if (rmdir(cidir) == 0)
+ ohshit(_("package control info contained directory '%.250s'"), cidir);
+ else if (errno != ENOTDIR)
+ ohshite(_("package control info rmdir of '%.250s' didn't say not a dir"),
+ de->d_name);
+
+ /* Ignore the control file. */
+ if (strcmp(de->d_name, CONTROLFILE) == 0) {
+ debug(dbg_scripts, "process_archive tmp.ci script/file '%s' is control",
+ cidir);
+ continue;
+ }
+ if (strcmp(de->d_name, LISTFILE) == 0) {
+ warning(_("package %s contained list as info file"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ continue;
+ }
+
+ /* Right, install it */
+ newinfofilename = pkg_infodb_get_file(pkg, &pkg->available, de->d_name);
+ if (rename(cidir, newinfofilename))
+ ohshite(_("unable to install new info file '%.250s' as '%.250s'"),
+ cidir, newinfofilename);
+
+ debug(dbg_scripts,
+ "process_archive tmp.ci script/file '%s' installed as '%s'",
+ cidir, newinfofilename);
+ }
+ pop_cleanup(ehflag_normaltidy); /* closedir */
+
+ /* If the old and new versions use a different infodb layout, get rid
+ * of the files using the old layout. */
+ if (pkg->installed.multiarch != pkg->available.multiarch &&
+ (pkg->installed.multiarch == PKG_MULTIARCH_SAME ||
+ pkg->available.multiarch == PKG_MULTIARCH_SAME)) {
+ debug(dbg_scripts,
+ "process_archive remove old info files after db layout switch");
+ pkg_infodb_foreach(pkg, &pkg->installed, pkg_infodb_remove_file);
+ }
+
+ dir_sync_path(pkg_infodb_get_dir());
+}
+
+static void
+pkg_remove_conffile_on_upgrade(struct pkginfo *pkg, struct fsys_namenode *namenode)
+{
+ struct pkginfo *otherpkg;
+ struct fsys_namenode *usenode;
+ struct fsys_node_pkgs_iter *iter;
+ struct varbuf cdr = VARBUF_INIT;
+ struct varbuf cdrext = VARBUF_INIT;
+ struct varbuf_state cdrext_state;
+ char currenthash[MD5HASHLEN + 1];
+ int rc;
+
+ usenode = namenodetouse(namenode, pkg, &pkg->installed);
+
+ rc = conffderef(pkg, &cdr, usenode->name);
+ if (rc == -1) {
+ debug(dbg_conffdetail, "%s: '%s' conffile dereference error: %s", __func__,
+ namenode->name, strerror(errno));
+ namenode->oldhash = EMPTYHASHFLAG;
+ return;
+ }
+
+ varbuf_reset(&cdrext);
+ varbuf_add_str(&cdrext, cdr.buf);
+ varbuf_end_str(&cdrext);
+
+ varbuf_snapshot(&cdrext, &cdrext_state);
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((otherpkg = fsys_node_pkgs_iter_next(iter))) {
+ debug(dbg_conffdetail, "%s: namenode '%s' owned by other %s?",
+ __func__, namenode->name, pkg_name(otherpkg, pnaw_always));
+
+ if (otherpkg == pkg)
+ continue;
+
+ debug(dbg_conff, "%s: namenode '%s' owned by other %s, remove-on-upgrade ignored",
+ __func__, namenode->name, pkg_name(otherpkg, pnaw_always));
+ fsys_node_pkgs_iter_free(iter);
+ return;
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ /* Remove DPKGDISTEXT variant if still present. */
+ varbuf_rollback(&cdrext_state);
+ varbuf_add_str(&cdrext, DPKGDISTEXT);
+ varbuf_end_str(&cdrext);
+
+ if (unlink(cdrext.buf) < 0 && errno != ENOENT)
+ warning(_("%s: failed to remove '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdrext.buf,
+ strerror(errno));
+
+ md5hash(pkg, currenthash, cdr.buf);
+
+ /* Has it been already removed (e.g. by local admin)? */
+ if (strcmp(currenthash, NONEXISTENTFLAG) == 0)
+ return;
+
+ /* For unmodified conffiles, we just remove them. */
+ if (strcmp(currenthash, namenode->oldhash) == 0) {
+ printf(_("Removing obsolete conffile %s ...\n"), cdr.buf);
+ if (unlink(cdr.buf) < 0 && errno != ENOENT)
+ warning(_("%s: failed to remove '%.250s': %s"),
+ pkg_name(pkg, pnaw_nonambig), cdr.buf, strerror(errno));
+ return;
+ }
+
+ /* Otherwise, preserve the modified conffile. */
+ varbuf_rollback(&cdrext_state);
+ varbuf_add_str(&cdrext, DPKGOLDEXT);
+ varbuf_end_str(&cdrext);
+
+ printf(_("Obsolete conffile '%s' has been modified by you.\n"), cdr.buf);
+ printf(_("Saving as %s ...\n"), cdrext.buf);
+ if (rename(cdr.buf, cdrext.buf) < 0)
+ warning(_("%s: cannot rename obsolete conffile '%s' to '%s': %s"),
+ pkg_name(pkg, pnaw_nonambig),
+ cdr.buf, cdrext.buf, strerror(errno));
+}
+
+static void
+pkg_remove_old_files(struct pkginfo *pkg,
+ struct fsys_namenode_queue *newfiles_queue,
+ struct fsys_namenode_queue *newconffiles)
+{
+ struct fsys_hash_rev_iter rev_iter;
+ struct fsys_namenode_list *cfile;
+ struct fsys_namenode *namenode;
+ struct stat stab, oldfs;
+
+ /* Before removing any old files, we try to remove obsolete conffiles that
+ * have been requested to be removed during upgrade. These conffiles are
+ * not tracked as part of the package file lists, so removing them here
+ * means we will get their parent directories removed if not present in the
+ * new package without needing to do anything special ourselves. */
+ for (cfile = newconffiles->head; cfile; cfile = cfile->next) {
+ debug(dbg_conffdetail, "%s: removing conffile '%s' for %s?", __func__,
+ cfile->namenode->name, pkg_name(pkg, pnaw_always));
+
+ if (!(cfile->namenode->flags & FNNF_RM_CONFF_ON_UPGRADE))
+ continue;
+
+ pkg_remove_conffile_on_upgrade(pkg, cfile->namenode);
+ }
+
+ fsys_hash_rev_iter_init(&rev_iter, pkg->files);
+
+ while ((namenode = fsys_hash_rev_iter_next(&rev_iter))) {
+ struct fsys_namenode *usenode;
+
+ if ((namenode->flags & FNNF_NEW_CONFF) ||
+ (namenode->flags & FNNF_RM_CONFF_ON_UPGRADE) ||
+ (namenode->flags & FNNF_NEW_INARCHIVE))
+ continue;
+
+ usenode = namenodetouse(namenode, pkg, &pkg->installed);
+
+ varbuf_rollback(&fname_state);
+ varbuf_add_str(&fnamevb, usenode->name);
+ varbuf_end_str(&fnamevb);
+
+ if (!stat(fnamevb.buf, &stab) && S_ISDIR(stab.st_mode)) {
+ debug(dbg_eachfiledetail, "process_archive: %s is a directory",
+ fnamevb.buf);
+ if (dir_is_used_by_others(namenode, pkg))
+ continue;
+ }
+
+ if (lstat(fnamevb.buf, &oldfs)) {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ warning(_("could not stat old file '%.250s' so not deleting it: %s"),
+ fnamevb.buf, strerror(errno));
+ continue;
+ }
+ if (S_ISDIR(oldfs.st_mode)) {
+ trig_path_activate(usenode, pkg);
+
+ /* Do not try to remove the root directory. */
+ if (strcmp(usenode->name, "/.") == 0)
+ continue;
+
+ if (rmdir(fnamevb.buf)) {
+ warning(_("unable to delete old directory '%.250s': %s"),
+ namenode->name, strerror(errno));
+ } else if ((namenode->flags & FNNF_OLD_CONFF)) {
+ warning(_("old conffile '%.250s' was an empty directory "
+ "(and has now been deleted)"), namenode->name);
+ }
+ } else {
+ struct fsys_namenode_list *sameas = NULL;
+ static struct file_ondisk_id empty_ondisk_id;
+ struct varbuf cfilename = VARBUF_INIT;
+
+ /*
+ * Ok, it's an old file, but is it really not in the new package?
+ * It might be known by a different name because of symlinks.
+ *
+ * We need to check to make sure, so we stat the file, then compare
+ * it to the new list. If we find a dev/inode match, we assume they
+ * are the same file, and leave it alone. NOTE: we don't check in
+ * other packages for sanity reasons (we don't want to stat _all_
+ * the files on the system).
+ *
+ * We run down the list of _new_ files in this package. This keeps
+ * the process a little leaner. We are only worried about new ones
+ * since ones that stayed the same don't really apply here.
+ */
+
+ /* If we can't stat the old or new file, or it's a directory,
+ * we leave it up to the normal code. */
+ debug(dbg_eachfile, "process_archive: checking %s for same files on "
+ "upgrade/downgrade", fnamevb.buf);
+
+ for (cfile = newfiles_queue->head; cfile; cfile = cfile->next) {
+ /* If the file has been filtered then treat it as if it didn't exist
+ * on the file system. */
+ if (cfile->namenode->flags & FNNF_FILTERED)
+ continue;
+
+ if (cfile->namenode->file_ondisk_id == NULL) {
+ struct stat tmp_stat;
+
+ varbuf_reset(&cfilename);
+ varbuf_add_str(&cfilename, dpkg_fsys_get_dir());
+ varbuf_add_str(&cfilename, cfile->namenode->name);
+ varbuf_end_str(&cfilename);
+
+ if (lstat(cfilename.buf, &tmp_stat) == 0) {
+ struct file_ondisk_id *file_ondisk_id;
+
+ file_ondisk_id = nfmalloc(sizeof(*file_ondisk_id));
+ file_ondisk_id->id_dev = tmp_stat.st_dev;
+ file_ondisk_id->id_ino = tmp_stat.st_ino;
+ cfile->namenode->file_ondisk_id = file_ondisk_id;
+ } else {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ ohshite(_("unable to stat other new file '%.250s'"),
+ cfile->namenode->name);
+ cfile->namenode->file_ondisk_id = &empty_ondisk_id;
+ continue;
+ }
+ }
+
+ if (cfile->namenode->file_ondisk_id == &empty_ondisk_id)
+ continue;
+
+ if (oldfs.st_dev == cfile->namenode->file_ondisk_id->id_dev &&
+ oldfs.st_ino == cfile->namenode->file_ondisk_id->id_ino) {
+ if (sameas)
+ warning(_("old file '%.250s' is the same as several new files! "
+ "(both '%.250s' and '%.250s')"), fnamevb.buf,
+ sameas->namenode->name, cfile->namenode->name);
+ sameas = cfile;
+ debug(dbg_eachfile, "process_archive: not removing %s, "
+ "since it matches %s", fnamevb.buf, cfile->namenode->name);
+ }
+ }
+
+ varbuf_destroy(&cfilename);
+
+ if ((namenode->flags & FNNF_OLD_CONFF)) {
+ if (sameas) {
+ if (sameas->namenode->flags & FNNF_NEW_CONFF) {
+ if (strcmp(sameas->namenode->oldhash, NEWCONFFILEFLAG) == 0) {
+ sameas->namenode->oldhash = namenode->oldhash;
+ debug(dbg_eachfile, "process_archive: old conff %s "
+ "is same as new conff %s, copying hash",
+ namenode->name, sameas->namenode->name);
+ } else {
+ debug(dbg_eachfile, "process_archive: old conff %s "
+ "is same as new conff %s but latter already has hash",
+ namenode->name, sameas->namenode->name);
+ }
+ }
+ } else {
+ debug(dbg_eachfile, "process_archive: old conff %s "
+ "is disappearing", namenode->name);
+ namenode->flags |= FNNF_OBS_CONFF;
+ tar_fsys_namenode_queue_push(newconffiles, namenode);
+ tar_fsys_namenode_queue_push(newfiles_queue, namenode);
+ }
+ continue;
+ }
+
+ if (sameas)
+ continue;
+
+ trig_path_activate(usenode, pkg);
+
+ if (secure_unlink_statted(fnamevb.buf, &oldfs)) {
+ warning(_("unable to securely remove old file '%.250s': %s"),
+ namenode->name, strerror(errno));
+ }
+ } /* !S_ISDIR */
+ }
+}
+
+static void
+pkg_update_fields(struct pkginfo *pkg, struct fsys_namenode_queue *newconffiles)
+{
+ struct dependency *newdeplist, **newdeplistlastp;
+ struct dependency *newdep, *dep;
+ struct deppossi **newpossilastp, *possi, *newpossi;
+ struct conffile **iconffileslastp, *newiconff;
+ struct fsys_namenode_list *cfile;
+
+ /* The dependencies are the most difficult. We have to build
+ * a whole new forward dependency tree. At least the reverse
+ * links (linking our deppossi's into the reverse chains)
+ * can be done by copy_dependency_links. */
+ newdeplist = NULL;
+ newdeplistlastp = &newdeplist;
+ for (dep = pkg->available.depends; dep; dep = dep->next) {
+ newdep = nfmalloc(sizeof(*newdep));
+ newdep->up = pkg;
+ newdep->next = NULL;
+ newdep->list = NULL;
+ newpossilastp = &newdep->list;
+
+ for (possi = dep->list; possi; possi = possi->next) {
+ newpossi = nfmalloc(sizeof(*newpossi));
+ newpossi->up = newdep;
+ newpossi->ed = possi->ed;
+ newpossi->next = NULL;
+ newpossi->rev_next = newpossi->rev_prev = NULL;
+ newpossi->arch_is_implicit = possi->arch_is_implicit;
+ newpossi->arch = possi->arch;
+ newpossi->verrel = possi->verrel;
+ if (possi->verrel != DPKG_RELATION_NONE)
+ newpossi->version = possi->version;
+ else
+ dpkg_version_blank(&newpossi->version);
+ newpossi->cyclebreak = false;
+ *newpossilastp = newpossi;
+ newpossilastp = &newpossi->next;
+ }
+ newdep->type = dep->type;
+ *newdeplistlastp = newdep;
+ newdeplistlastp = &newdep->next;
+ }
+
+ /* Right, now we've replicated the forward tree, we
+ * get copy_dependency_links to remove all the old dependency
+ * structures from the reverse links and add the new dependency
+ * structures in instead. It also copies the new dependency
+ * structure pointer for this package into the right field. */
+ copy_dependency_links(pkg, &pkg->installed.depends, newdeplist, 0);
+
+ /* We copy the text fields. */
+ pkg->installed.essential = pkg->available.essential;
+ pkg->installed.is_protected = pkg->available.is_protected;
+ pkg->installed.multiarch = pkg->available.multiarch;
+ pkg->installed.description = pkg->available.description;
+ pkg->installed.maintainer = pkg->available.maintainer;
+ pkg->installed.source = pkg->available.source;
+ pkg->installed.arch = pkg->available.arch;
+ pkg->installed.pkgname_archqual = pkg->available.pkgname_archqual;
+ pkg->installed.installedsize = pkg->available.installedsize;
+ pkg->installed.version = pkg->available.version;
+ pkg->installed.origin = pkg->available.origin;
+ pkg->installed.bugs = pkg->available.bugs;
+
+ /* We have to generate our own conffiles structure. */
+ pkg->installed.conffiles = NULL;
+ iconffileslastp = &pkg->installed.conffiles;
+ for (cfile = newconffiles->head; cfile; cfile = cfile->next) {
+ newiconff = nfmalloc(sizeof(*newiconff));
+ newiconff->next = NULL;
+ newiconff->name = nfstrsave(cfile->namenode->name);
+ newiconff->hash = nfstrsave(cfile->namenode->oldhash);
+ newiconff->obsolete = !!(cfile->namenode->flags & FNNF_OBS_CONFF);
+ newiconff->remove_on_upgrade = !!(
+ cfile->namenode->flags & FNNF_RM_CONFF_ON_UPGRADE);
+ *iconffileslastp = newiconff;
+ iconffileslastp = &newiconff->next;
+ }
+
+ /* We can just copy the arbitrary fields list, because it is
+ * never even rearranged. Phew! */
+ pkg->installed.arbs = pkg->available.arbs;
+}
+
+static void
+pkg_disappear(struct pkginfo *pkg, struct pkginfo *infavour)
+{
+ printf(_("(Noting disappearance of %s, which has been completely replaced.)\n"),
+ pkg_name(pkg, pnaw_nonambig));
+ log_action("disappear", pkg, &pkg->installed);
+ debug(dbg_general, "pkg_disappear disappearing %s",
+ pkg_name(pkg, pnaw_always));
+
+ trig_activate_packageprocessing(pkg);
+ maintscript_installed(pkg, POSTRMFILE,
+ "post-removal script (for disappearance)",
+ "disappear",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ NULL);
+
+ /* OK, now we delete all the stuff in the ‘info’ directory ... */
+ debug(dbg_general, "pkg_disappear cleaning info directory");
+ pkg_infodb_foreach(pkg, &pkg->installed, pkg_infodb_remove_file);
+ dir_sync_path(pkg_infodb_get_dir());
+
+ pkg_set_status(pkg, PKG_STAT_NOTINSTALLED);
+ pkg_set_want(pkg, PKG_WANT_UNKNOWN);
+ pkg_reset_eflags(pkg);
+
+ dpkg_version_blank(&pkg->configversion);
+ pkgbin_blank(&pkg->installed);
+
+ pkg->files_list_valid = false;
+
+ modstatdb_note(pkg);
+}
+
+static void
+pkg_disappear_others(struct pkginfo *pkg)
+{
+ struct pkg_hash_iter *iter;
+ struct pkginfo *otherpkg;
+ struct fsys_namenode_list *cfile;
+ struct deppossi *pdep;
+ struct dependency *providecheck;
+ struct varbuf depprobwhy = VARBUF_INIT;
+
+ iter = pkg_hash_iter_new();
+ while ((otherpkg = pkg_hash_iter_next_pkg(iter)) != NULL) {
+ ensure_package_clientdata(otherpkg);
+
+ if (otherpkg == pkg ||
+ otherpkg->status == PKG_STAT_NOTINSTALLED ||
+ otherpkg->status == PKG_STAT_CONFIGFILES ||
+ otherpkg->clientdata->istobe == PKG_ISTOBE_REMOVE ||
+ !otherpkg->files)
+ continue;
+
+ /* Do not try to disappear other packages from the same set
+ * if they are Multi-Arch: same */
+ if (pkg->installed.multiarch == PKG_MULTIARCH_SAME &&
+ otherpkg->installed.multiarch == PKG_MULTIARCH_SAME &&
+ otherpkg->set == pkg->set)
+ continue;
+
+ debug(dbg_veryverbose, "process_archive checking disappearance %s",
+ pkg_name(otherpkg, pnaw_always));
+
+ if (otherpkg->clientdata->istobe != PKG_ISTOBE_NORMAL &&
+ otherpkg->clientdata->istobe != PKG_ISTOBE_DECONFIGURE)
+ internerr("disappearing package %s is not to be normal or deconfigure, "
+ "is to be %d",
+ pkg_name(otherpkg, pnaw_always), otherpkg->clientdata->istobe);
+
+ for (cfile = otherpkg->files;
+ cfile && strcmp(cfile->namenode->name, "/.") == 0;
+ cfile = cfile->next);
+ if (!cfile) {
+ debug(dbg_stupidlyverbose, "process_archive no non-root, no disappear");
+ continue;
+ }
+ for (cfile = otherpkg->files;
+ cfile && !filesavespackage(cfile, otherpkg, pkg);
+ cfile = cfile->next);
+ if (cfile)
+ continue;
+
+ /* So dependency things will give right answers ... */
+ otherpkg->clientdata->istobe = PKG_ISTOBE_REMOVE;
+ debug(dbg_veryverbose, "process_archive disappear checking dependencies");
+ for (pdep = otherpkg->set->depended.installed;
+ pdep;
+ pdep = pdep->rev_next) {
+ if (pdep->up->type != dep_depends &&
+ pdep->up->type != dep_predepends &&
+ pdep->up->type != dep_recommends)
+ continue;
+
+ if (depisok(pdep->up, &depprobwhy, NULL, NULL, false))
+ continue;
+
+ varbuf_end_str(&depprobwhy);
+ debug(dbg_veryverbose,"process_archive cannot disappear: %s",
+ depprobwhy.buf);
+ break;
+ }
+ if (!pdep) {
+ /* If we haven't found a reason not to yet, let's look some more. */
+ for (providecheck = otherpkg->installed.depends;
+ providecheck;
+ providecheck = providecheck->next) {
+ if (providecheck->type != dep_provides)
+ continue;
+
+ for (pdep = providecheck->list->ed->depended.installed;
+ pdep;
+ pdep = pdep->rev_next) {
+ if (pdep->up->type != dep_depends &&
+ pdep->up->type != dep_predepends &&
+ pdep->up->type != dep_recommends)
+ continue;
+
+ if (depisok(pdep->up, &depprobwhy, NULL, NULL, false))
+ continue;
+
+ varbuf_end_str(&depprobwhy);
+ debug(dbg_veryverbose,
+ "process_archive cannot disappear (provides %s): %s",
+ providecheck->list->ed->name, depprobwhy.buf);
+ goto break_from_both_loops_at_once;
+ }
+ }
+ break_from_both_loops_at_once:;
+ }
+ otherpkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
+ if (pdep)
+ continue;
+
+ /* No, we're disappearing it. This is the wrong time to go and
+ * run maintainer scripts and things, as we can't back out. But
+ * what can we do ? It has to be run this late. */
+ pkg_disappear(otherpkg, pkg);
+ } /* while (otherpkg= ... */
+ pkg_hash_iter_free(iter);
+}
+
+/**
+ * Check if all instances of a pkgset are getting in sync.
+ *
+ * If that's the case, the extraction is going to ensure consistency
+ * of shared files.
+ */
+static bool
+pkgset_getting_in_sync(struct pkginfo *pkg)
+{
+ struct pkginfo *otherpkg;
+
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->status <= PKG_STAT_CONFIGFILES)
+ continue;
+ if (dpkg_version_compare(&pkg->available.version,
+ &otherpkg->installed.version)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void
+pkg_remove_files_from_others(struct pkginfo *pkg, struct fsys_namenode_list *newfileslist)
+{
+ struct fsys_namenode_list *cfile;
+ struct pkginfo *otherpkg;
+
+ for (cfile = newfileslist; cfile; cfile = cfile->next) {
+ struct fsys_node_pkgs_iter *iter;
+ struct pkgset *divpkgset;
+
+ if (!(cfile->namenode->flags & FNNF_ELIDE_OTHER_LISTS))
+ continue;
+
+ if (cfile->namenode->divert && cfile->namenode->divert->useinstead) {
+ divpkgset = cfile->namenode->divert->pkgset;
+ if (divpkgset == pkg->set) {
+ debug(dbg_eachfile,
+ "process_archive not overwriting any '%s' (overriding, '%s')",
+ cfile->namenode->name, cfile->namenode->divert->useinstead->name);
+ continue;
+ } else {
+ debug(dbg_eachfile,
+ "process_archive looking for overwriting '%s' (overridden by %s)",
+ cfile->namenode->name, divpkgset ? divpkgset->name : "<local>");
+ }
+ } else {
+ divpkgset = NULL;
+ debug(dbg_eachfile, "process_archive looking for overwriting '%s'",
+ cfile->namenode->name);
+ }
+
+ iter = fsys_node_pkgs_iter_new(cfile->namenode);
+ while ((otherpkg = fsys_node_pkgs_iter_next(iter))) {
+ debug(dbg_eachfiledetail, "process_archive ... found in %s",
+ pkg_name(otherpkg, pnaw_always));
+
+ /* A pkgset can share files between instances, so there's no point
+ * in rewriting the file that's already in place. */
+ if (otherpkg->set == pkg->set)
+ continue;
+
+ if (otherpkg->set == divpkgset) {
+ debug(dbg_eachfiledetail, "process_archive ... diverted, skipping");
+ continue;
+ }
+
+ if (cfile->namenode->flags & FNNF_NEW_CONFF)
+ conffile_mark_obsolete(otherpkg, cfile->namenode);
+
+ /* If !files_list_valid then it's one of the disappeared packages above
+ * or we have already updated the files list file, and we don't bother
+ * with it here, clearly. */
+ if (!otherpkg->files_list_valid)
+ continue;
+
+ /* Found one. We delete the list entry for this file,
+ * (and any others in the same package) and then mark the package
+ * as requiring a reread. */
+ write_filelist_except(otherpkg, &otherpkg->installed,
+ otherpkg->files, FNNF_ELIDE_OTHER_LISTS);
+ debug(dbg_veryverbose, "process_archive overwrote from %s",
+ pkg_name(otherpkg, pnaw_always));
+ }
+ fsys_node_pkgs_iter_free(iter);
+ }
+}
+
+static void
+pkg_remove_backup_files(struct pkginfo *pkg, struct fsys_namenode_list *newfileslist)
+{
+ struct fsys_namenode_list *cfile;
+
+ for (cfile = newfileslist; cfile; cfile = cfile->next) {
+ struct fsys_namenode *usenode;
+
+ if (cfile->namenode->flags & FNNF_NEW_CONFF)
+ continue;
+
+ usenode = namenodetouse(cfile->namenode, pkg, &pkg->installed);
+
+ /* Do not try to remove backups for the root directory. */
+ if (strcmp(usenode->name, "/.") == 0)
+ continue;
+
+ varbuf_rollback(&fnametmp_state);
+ varbuf_add_str(&fnametmpvb, usenode->name);
+ varbuf_add_str(&fnametmpvb, DPKGTEMPEXT);
+ varbuf_end_str(&fnametmpvb);
+ path_remove_tree(fnametmpvb.buf);
+ }
+}
+
+void process_archive(const char *filename) {
+ static const struct tar_operations tf = {
+ .read = tarfileread,
+ .extract_file = tarobject,
+ .link = tarobject,
+ .symlink = tarobject,
+ .mkdir = tarobject,
+ .mknod = tarobject,
+ };
+
+ /* These need to be static so that we can pass their addresses to
+ * push_cleanup as arguments to the cu_xxx routines; if an error occurs
+ * we unwind the stack before processing the cleanup list, and these
+ * variables had better still exist ... */
+ static int p1[2];
+ static enum pkgstatus oldversionstatus;
+ static struct tarcontext tc;
+
+ struct tar_archive tar;
+ struct dpkg_error err;
+ enum parsedbflags parsedb_flags;
+ int rc;
+ pid_t pid;
+ struct pkginfo *pkg, *otherpkg;
+ struct pkg_list *conflictor_iter;
+ char *cidir = NULL;
+ char *cidirrest;
+ char *psize;
+ const char *pfilename;
+ struct fsys_namenode_queue newconffiles, newfiles_queue;
+ struct stat stab;
+
+ cleanup_pkg_failed= cleanup_conflictor_failed= 0;
+
+ pfilename = summarize_filename(filename);
+
+ if (stat(filename, &stab))
+ ohshite(_("cannot access archive '%s'"), filename);
+
+ /* We can't ‘tentatively-reassemble’ packages. */
+ if (!f_noact) {
+ if (!deb_reassemble(&filename, &pfilename))
+ return;
+ }
+
+ /* Verify the package. */
+ if (!f_nodebsig)
+ deb_verify(filename);
+
+ /* Get the control information directory. */
+ cidir = get_control_dir(cidir);
+ cidirrest = cidir + strlen(cidir);
+ push_cleanup(cu_cidir, ~0, 2, (void *)cidir, (void *)cidirrest);
+
+ pid = subproc_fork();
+ if (pid == 0) {
+ cidirrest[-1] = '\0';
+ execlp(BACKEND, BACKEND, "--control", filename, cidir, NULL);
+ ohshite(_("unable to execute %s (%s)"),
+ _("package control information extraction"), BACKEND);
+ }
+ subproc_reap(pid, BACKEND " --control", 0);
+
+ /* We want to guarantee the extracted files are on the disk, so that the
+ * subsequent renames to the info database do not end up with old or zero
+ * length files in case of a system crash. As neither dpkg-deb nor tar do
+ * explicit fsync()s, we have to do them here.
+ * XXX: This could be avoided by switching to an internal tar extractor. */
+ dir_sync_contents(cidir);
+
+ strcpy(cidirrest,CONTROLFILE);
+
+ if (cipaction->arg_int == act_avail)
+ parsedb_flags = pdb_parse_available;
+ else
+ parsedb_flags = pdb_parse_binary;
+ parsedb_flags |= pdb_ignore_archives;
+ if (in_force(FORCE_BAD_VERSION))
+ parsedb_flags |= pdb_lax_version_parser;
+
+ parsedb(cidir, parsedb_flags, &pkg);
+
+ if (!pkg->archives) {
+ pkg->archives = nfmalloc(sizeof(*pkg->archives));
+ pkg->archives->next = NULL;
+ pkg->archives->name = NULL;
+ pkg->archives->msdosname = NULL;
+ pkg->archives->md5sum = NULL;
+ }
+ /* Always nfmalloc. Otherwise, we may overwrite some other field (like
+ * md5sum). */
+ psize = nfmalloc(30);
+ sprintf(psize, "%jd", (intmax_t)stab.st_size);
+ pkg->archives->size = psize;
+
+ if (cipaction->arg_int == act_avail) {
+ printf(_("Recorded info about %s from %s.\n"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig), pfilename);
+ pop_cleanup(ehflag_normaltidy);
+ return;
+ }
+
+ if (pkg->available.arch->type != DPKG_ARCH_ALL &&
+ pkg->available.arch->type != DPKG_ARCH_NATIVE &&
+ pkg->available.arch->type != DPKG_ARCH_FOREIGN)
+ forcibleerr(FORCE_ARCHITECTURE,
+ _("package architecture (%s) does not match system (%s)"),
+ pkg->available.arch->name,
+ dpkg_arch_get(DPKG_ARCH_NATIVE)->name);
+
+ clear_deconfigure_queue();
+ clear_istobes();
+
+ if (wanttoinstall(pkg)) {
+ pkg_set_want(pkg, PKG_WANT_INSTALL);
+ } else {
+ pop_cleanup(ehflag_normaltidy);
+ return;
+ }
+
+ /* Deconfigure other instances from a pkgset if they are not in sync. */
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->status <= PKG_STAT_HALFCONFIGURED)
+ continue;
+
+ if (dpkg_version_compare(&pkg->available.version,
+ &otherpkg->installed.version))
+ enqueue_deconfigure(otherpkg, NULL, PKG_WANT_UNKNOWN);
+ }
+
+ pkg_check_depcon(pkg, pfilename);
+
+ ensure_allinstfiles_available();
+ fsys_hash_init();
+ trig_file_interests_ensure();
+
+ printf(_("Preparing to unpack %s ...\n"), pfilename);
+
+ if (pkg->status != PKG_STAT_NOTINSTALLED &&
+ pkg->status != PKG_STAT_CONFIGFILES) {
+ log_action("upgrade", pkg, &pkg->installed);
+ } else {
+ log_action("install", pkg, &pkg->available);
+ }
+
+ if (f_noact) {
+ pop_cleanup(ehflag_normaltidy);
+ return;
+ }
+
+ /*
+ * OK, we're going ahead.
+ */
+
+ trig_activate_packageprocessing(pkg);
+ strcpy(cidirrest, TRIGGERSCIFILE);
+ trig_parse_ci(cidir, NULL, trig_cicb_statuschange_activate, pkg, &pkg->available);
+
+ /* Read the conffiles, and copy the hashes across. */
+ newconffiles.head = NULL;
+ newconffiles.tail = &newconffiles.head;
+ push_cleanup(cu_fileslist, ~0, 0);
+ strcpy(cidirrest,CONFFILESFILE);
+ deb_parse_conffiles(pkg, cidir, &newconffiles);
+
+ /* All the old conffiles are marked with a flag, so that we don't delete
+ * them if they seem to disappear completely. */
+ pkg_conffiles_mark_old(pkg);
+ for (conflictor_iter = conflictors.head;
+ conflictor_iter;
+ conflictor_iter = conflictor_iter->next)
+ pkg_conffiles_mark_old(conflictor_iter->pkg);
+
+ oldversionstatus= pkg->status;
+
+ if (oldversionstatus > PKG_STAT_INSTALLED)
+ internerr("package %s state %d is out-of-bounds",
+ pkg_name(pkg, pnaw_always), oldversionstatus);
+
+ debug(dbg_general,"process_archive oldversionstatus=%s",
+ statusstrings[oldversionstatus]);
+
+ if (oldversionstatus == PKG_STAT_HALFCONFIGURED ||
+ oldversionstatus == PKG_STAT_TRIGGERSAWAITED ||
+ oldversionstatus == PKG_STAT_TRIGGERSPENDING ||
+ oldversionstatus == PKG_STAT_INSTALLED) {
+ pkg_set_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(pkg);
+ push_cleanup(cu_prermupgrade, ~ehflag_normaltidy, 1, (void *)pkg);
+ maintscript_fallback(pkg, PRERMFILE, "pre-removal", cidir, cidirrest,
+ "upgrade", "failed-upgrade");
+ pkg_set_status(pkg, PKG_STAT_UNPACKED);
+ oldversionstatus = PKG_STAT_UNPACKED;
+ modstatdb_note(pkg);
+ }
+
+ pkg_deconfigure_others(pkg);
+
+ for (conflictor_iter = conflictors.head;
+ conflictor_iter;
+ conflictor_iter = conflictor_iter->next) {
+ struct pkginfo *conflictor = conflictor_iter->pkg;
+
+ if (!(conflictor->status == PKG_STAT_HALFCONFIGURED ||
+ conflictor->status == PKG_STAT_TRIGGERSAWAITED ||
+ conflictor->status == PKG_STAT_TRIGGERSPENDING ||
+ conflictor->status == PKG_STAT_INSTALLED))
+ continue;
+
+ trig_activate_packageprocessing(conflictor);
+ pkg_set_status(conflictor, PKG_STAT_HALFCONFIGURED);
+ modstatdb_note(conflictor);
+ push_cleanup(cu_prerminfavour, ~ehflag_normaltidy,
+ 2, conflictor, pkg);
+ maintscript_installed(conflictor, PRERMFILE, "pre-removal",
+ "remove", "in-favour",
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ versiondescribe(&pkg->available.version,
+ vdew_nonambig),
+ NULL);
+ pkg_set_status(conflictor, PKG_STAT_HALFINSTALLED);
+ modstatdb_note(conflictor);
+ }
+
+ pkg_set_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ if (pkg->status == PKG_STAT_NOTINSTALLED) {
+ pkg->installed.version= pkg->available.version;
+ pkg->installed.multiarch = pkg->available.multiarch;
+ }
+ pkg_set_status(pkg, PKG_STAT_HALFINSTALLED);
+ modstatdb_note(pkg);
+ if (oldversionstatus == PKG_STAT_NOTINSTALLED) {
+ push_cleanup(cu_preinstverynew, ~ehflag_normaltidy,
+ 3,(void*)pkg,(void*)cidir,(void*)cidirrest);
+ maintscript_new(pkg, PREINSTFILE, "pre-installation", cidir, cidirrest,
+ "install", NULL);
+ } else if (oldversionstatus == PKG_STAT_CONFIGFILES) {
+ push_cleanup(cu_preinstnew, ~ehflag_normaltidy,
+ 3,(void*)pkg,(void*)cidir,(void*)cidirrest);
+ maintscript_new(pkg, PREINSTFILE, "pre-installation", cidir, cidirrest,
+ "install",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ } else {
+ push_cleanup(cu_preinstupgrade, ~ehflag_normaltidy,
+ 4,(void*)pkg,(void*)cidir,(void*)cidirrest,(void*)&oldversionstatus);
+ maintscript_new(pkg, PREINSTFILE, "pre-installation", cidir, cidirrest,
+ "upgrade",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ }
+
+ if (oldversionstatus == PKG_STAT_NOTINSTALLED ||
+ oldversionstatus == PKG_STAT_CONFIGFILES) {
+ printf(_("Unpacking %s (%s) ...\n"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig));
+ } else {
+ printf(_("Unpacking %s (%s) over (%s) ...\n"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ }
+
+ /*
+ * Now we unpack the archive, backing things up as we go.
+ * For each file, we check to see if it already exists.
+ * There are several possibilities:
+ *
+ * + We are trying to install a non-directory ...
+ * - It doesn't exist. In this case we simply extract it.
+ * - It is a plain file, device, symlink, &c. We do an ‘atomic
+ * overwrite’ using link() and rename(), but leave a backup copy.
+ * Later, when we delete the backup, we remove it from any other
+ * packages' lists.
+ * - It is a directory. In this case it depends on whether we're
+ * trying to install a symlink or something else.
+ * = If we're not trying to install a symlink we move the directory
+ * aside and extract the node. Later, when we recursively remove
+ * the backed-up directory, we remove it from any other packages'
+ * lists.
+ * = If we are trying to install a symlink we do nothing - ie,
+ * dpkg will never replace a directory tree with a symlink. This
+ * is to avoid embarrassing effects such as replacing a directory
+ * tree with a link to a link to the original directory tree.
+ * + We are trying to install a directory ...
+ * - It doesn't exist. We create it with the appropriate modes.
+ * - It exists as a directory or a symlink to one. We do nothing.
+ * - It is a plain file or a symlink (other than to a directory).
+ * We move it aside and create the directory. Later, when we
+ * delete the backup, we remove it from any other packages' lists.
+ *
+ * Install non-dir Install symlink Install dir
+ * Exists not X X X
+ * File/node/symlink LXR LXR BXR
+ * Directory BXR - -
+ *
+ * X: extract file/node/link/directory
+ * LX: atomic overwrite leaving backup
+ * B: ordinary backup
+ * R: later remove from other packages' lists
+ * -: do nothing
+ *
+ * After we've done this we go through the remaining things in the
+ * lists of packages we're trying to remove (including the old
+ * version of the current package). This happens in reverse order,
+ * so that we process files before the directories (or symlinks-to-
+ * directories) containing them.
+ *
+ * + If the thing is a conffile then we leave it alone for the purge
+ * operation.
+ * + Otherwise, there are several possibilities too:
+ * - The listed thing does not exist. We ignore it.
+ * - The listed thing is a directory or a symlink to a directory.
+ * We delete it only if it isn't listed in any other package.
+ * - The listed thing is not a directory, but was part of the package
+ * that was upgraded, we check to make sure the files aren't the
+ * same ones from the old package by checking dev/inode
+ * - The listed thing is not a directory or a symlink to one (ie,
+ * it's a plain file, device, pipe, &c, or a symlink to one, or a
+ * dangling symlink). We delete it.
+ *
+ * The removed packages' list becomes empty (of course, the new
+ * version of the package we're installing will have a new list,
+ * which replaces the old version's list).
+ *
+ * If at any stage we remove a file from a package's list, and the
+ * package isn't one we're already processing, and the package's
+ * list becomes empty as a result, we ‘vanish’ the package. This
+ * means that we run its postrm with the ‘disappear’ argument, and
+ * put the package in the ‘not-installed’ state. If it had any
+ * conffiles, their hashes and ownership will have been transferred
+ * already, so we just ignore those and forget about them from the
+ * point of view of the disappearing package.
+ *
+ * NOTE THAT THE OLD POSTRM IS RUN AFTER THE NEW PREINST, since the
+ * files get replaced ‘as we go’.
+ */
+
+ m_pipe(p1);
+ push_cleanup(cu_closepipe, ehflag_bombout, 1, (void *)&p1[0]);
+ pid = subproc_fork();
+ if (pid == 0) {
+ m_dup2(p1[1],1); close(p1[0]); close(p1[1]);
+ execlp(BACKEND, BACKEND, "--fsys-tarfile", filename, NULL);
+ ohshite(_("unable to execute %s (%s)"),
+ _("package filesystem archive extraction"), BACKEND);
+ }
+ close(p1[1]);
+ p1[1] = -1;
+
+ newfiles_queue.head = NULL;
+ newfiles_queue.tail = &newfiles_queue.head;
+ tc.newfiles_queue = &newfiles_queue;
+ push_cleanup(cu_fileslist, ~0, 0);
+ tc.pkg= pkg;
+ tc.backendpipe= p1[0];
+ tc.pkgset_getting_in_sync = pkgset_getting_in_sync(pkg);
+
+ /* Setup the tar archive. */
+ tar.err = DPKG_ERROR_OBJECT;
+ tar.ctx = &tc;
+ tar.ops = &tf;
+
+ rc = tar_extractor(&tar);
+ if (rc)
+ dpkg_error_print(&tar.err,
+ _("corrupted filesystem tarfile in package archive"));
+ if (fd_skip(p1[0], -1, &err) < 0)
+ ohshit(_("cannot zap possible trailing zeros from dpkg-deb: %s"), err.str);
+ close(p1[0]);
+ p1[0] = -1;
+ subproc_reap(pid, BACKEND " --fsys-tarfile", SUBPROC_NOPIPE);
+
+ tar_deferred_extract(newfiles_queue.head, pkg);
+
+ if (oldversionstatus == PKG_STAT_HALFINSTALLED ||
+ oldversionstatus == PKG_STAT_UNPACKED) {
+ /* Packages that were in ‘installed’ and ‘postinstfailed’ have been
+ * reduced to ‘unpacked’ by now, by the running of the prerm script. */
+ pkg_set_status(pkg, PKG_STAT_HALFINSTALLED);
+ modstatdb_note(pkg);
+ push_cleanup(cu_postrmupgrade, ~ehflag_normaltidy, 1, (void *)pkg);
+ maintscript_fallback(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "upgrade", "failed-upgrade");
+ }
+
+ /* If anything goes wrong while tidying up it's a bit late to do
+ * anything about it. However, we don't install the new status
+ * info yet, so that a future dpkg installation will put everything
+ * right (we hope).
+ *
+ * If something does go wrong later the ‘conflictor’ package will be
+ * left in the ‘removal_failed’ state. Removing or installing it
+ * will be impossible if it was required because of the conflict with
+ * the package we're installing now and (presumably) the dependency
+ * by other packages. This means that the files it contains in
+ * common with this package will hang around until we successfully
+ * get this package installed, after which point we can trust the
+ * conflicting package's file list, which will have been updated to
+ * remove any files in this package. */
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+ /* Now we delete all the files that were in the old version of
+ * the package only, except (old or new) conffiles, which we leave
+ * alone. */
+ pkg_remove_old_files(pkg, &newfiles_queue, &newconffiles);
+
+ /* OK, now we can write the updated files-in-this package list,
+ * since we've done away (hopefully) with all the old junk. */
+ write_filelist_except(pkg, &pkg->available, newfiles_queue.head, 0);
+
+ /* Trigger interests may have changed.
+ * Firstly we go through the old list of interests deleting them.
+ * Then we go through the new list adding them. */
+ strcpy(cidirrest, TRIGGERSCIFILE);
+ trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed, TRIGGERSCIFILE),
+ trig_cicb_interest_delete, NULL, pkg, &pkg->installed);
+ trig_parse_ci(cidir, trig_cicb_interest_add, NULL, pkg, &pkg->available);
+ trig_file_interests_save();
+
+ /* We also install the new maintainer scripts, and any other
+ * cruft that may have come along with the package. First
+ * we go through the existing scripts replacing or removing
+ * them as appropriate; then we go through the new scripts
+ * (any that are left) and install them. */
+ debug(dbg_general, "process_archive updating info directory");
+ pkg_infodb_update(pkg, cidir, cidirrest);
+
+ /* We store now the checksums dynamically computed while unpacking. */
+ write_filehash_except(pkg, &pkg->available, newfiles_queue.head, 0);
+
+ /*
+ * Update the status database.
+ *
+ * This involves copying each field across from the ‘available’
+ * to the ‘installed’ half of the pkg structure.
+ * For some of the fields we have to do a complicated construction
+ * operation; for others we can just copy the value.
+ * We tackle the fields in the order they appear, so that
+ * we don't miss any out :-).
+ * At least we don't have to copy any strings that are referred
+ * to, because these are never modified and never freed.
+ */
+ pkg_update_fields(pkg, &newconffiles);
+
+ /* In case this was an architecture cross-grade, the in-core pkgset might
+ * be in an inconsistent state, with two pkginfo entries having the same
+ * architecture, so let's fix that. Note that this does not lose data,
+ * as the pkg.available member parsed from the binary should replace the
+ * to be cleared duplicate in the other instance. */
+ for (otherpkg = &pkg->set->pkg; otherpkg; otherpkg = otherpkg->arch_next) {
+ if (otherpkg == pkg)
+ continue;
+ if (otherpkg->installed.arch != pkg->installed.arch)
+ continue;
+
+ if (otherpkg->status != PKG_STAT_NOTINSTALLED)
+ internerr("other package %s instance in state %s instead of not-installed",
+ pkg_name(otherpkg, pnaw_always), pkg_status_name(otherpkg));
+
+ pkg_blank(otherpkg);
+ }
+
+ /* Check for disappearing packages:
+ * We go through all the packages on the system looking for ones
+ * whose files are entirely part of the one we've just unpacked
+ * (and which actually *have* some files!).
+ *
+ * Any that we find are removed - we run the postrm with ‘disappear’
+ * as an argument, and remove their info/... files and status info.
+ * Conffiles are ignored (the new package had better do something
+ * with them!). */
+ pkg_disappear_others(pkg);
+
+ /* Delete files from any other packages' lists.
+ * We have to do this before we claim this package is in any
+ * sane kind of state, as otherwise we might delete by mistake
+ * a file that we overwrote, when we remove the package which
+ * had the version we overwrote. To prevent this we make
+ * sure that we don't claim this package is OK until we
+ * have claimed ‘ownership’ of all its files. */
+ pkg_remove_files_from_others(pkg, newfiles_queue.head);
+
+ /* Right, the package we've unpacked is now in a reasonable state.
+ * The only thing that we have left to do with it is remove
+ * backup files, and we can leave the user to fix that if and when
+ * it happens (we leave the reinstall required flag, of course). */
+ pkg_set_status(pkg, PKG_STAT_UNPACKED);
+ modstatdb_note(pkg);
+
+ /* Now we delete all the backup files that we made when
+ * extracting the archive - except for files listed as conffiles
+ * in the new package.
+ * This time we count it as an error if something goes wrong.
+ *
+ * Note that we don't ever delete things that were in the old
+ * package as a conffile and don't appear at all in the new.
+ * They stay recorded as obsolete conffiles and will eventually
+ * (if not taken over by another package) be forgotten. */
+ pkg_remove_backup_files(pkg, newfiles_queue.head);
+
+ /* OK, we're now fully done with the main package.
+ * This is quite a nice state, so we don't unwind past here. */
+ pkg_reset_eflags(pkg);
+ modstatdb_note(pkg);
+ push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+ /* Only the removal of the conflictor left to do.
+ * The files list for the conflictor is still a little inconsistent in-core,
+ * as we have not yet updated the filename->packages mappings; however,
+ * the package->filenames mapping is. */
+ while (!pkg_queue_is_empty(&conflictors)) {
+ struct pkginfo *conflictor = pkg_queue_pop(&conflictors);
+
+ /* We need to have the most up-to-date info about which files are
+ * what ... */
+ ensure_allinstfiles_available();
+ printf(_("Removing %s (%s), to allow configuration of %s (%s) ...\n"),
+ pkg_name(conflictor, pnaw_nonambig),
+ versiondescribe(&conflictor->installed.version, vdew_nonambig),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig));
+ removal_bulk(conflictor);
+ }
+
+ if (cipaction->arg_int == act_install)
+ enqueue_package_mark_seen(pkg);
+}
diff --git a/src/main/update.c b/src/main/update.c
new file mode 100644
index 0000000..4a9a95b
--- /dev/null
+++ b/src/main/update.c
@@ -0,0 +1,124 @@
+/*
+ * dpkg - main program for package management
+ * update.c - options which update the ‘available’ database
+ *
+ * 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 <errno.h>
+#include <string.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/options.h>
+
+#include "main.h"
+
+int
+updateavailable(const char *const *argv)
+{
+ const char *sourcefile= argv[0];
+ char *availfile;
+ int count= 0;
+
+ modstatdb_init();
+
+ switch (cipaction->arg_int) {
+ case act_avclear:
+ if (sourcefile) badusage(_("--%s takes no arguments"),cipaction->olong);
+ break;
+ case act_avreplace: case act_avmerge:
+ if (sourcefile == NULL)
+ sourcefile = "-";
+ else if (argv[1])
+ badusage(_("--%s takes at most one Packages-file argument"),
+ cipaction->olong);
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+
+ if (!f_noact) {
+ const char *dbdir = dpkg_db_get_dir();
+
+ if (access(dbdir, W_OK)) {
+ if (errno != EACCES)
+ ohshite(_("unable to access dpkg database directory '%s' for bulk available update"),
+ dbdir);
+ else
+ ohshit(_("required write access to dpkg database directory '%s' for bulk available update"),
+ dbdir);
+ }
+ modstatdb_lock();
+ }
+
+ switch (cipaction->arg_int) {
+ case act_avreplace:
+ printf(_("Replacing available packages info, using %s.\n"),sourcefile);
+ break;
+ case act_avmerge:
+ printf(_("Updating available packages info, using %s.\n"),sourcefile);
+ break;
+ case act_avclear:
+ break;
+ default:
+ internerr("unknown action '%d'", cipaction->arg_int);
+ }
+
+ availfile = dpkg_db_get_path(AVAILFILE);
+
+ if (cipaction->arg_int == act_avmerge)
+ parsedb(availfile, pdb_parse_available, NULL);
+
+ if (cipaction->arg_int != act_avclear)
+ count += parsedb(sourcefile,
+ pdb_parse_available | pdb_ignoreolder | pdb_dash_is_stdin,
+ NULL);
+
+ if (!f_noact) {
+ writedb(availfile, wdb_dump_available);
+ modstatdb_unlock();
+ }
+
+ free(availfile);
+
+ if (cipaction->arg_int != act_avclear)
+ printf(P_("Information about %d package was updated.\n",
+ "Information about %d packages was updated.\n", count), count);
+
+ modstatdb_done();
+
+ return 0;
+}
+
+int
+forgetold(const char *const *argv)
+{
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ warning(_("obsolete '--%s' option; unavailable packages are automatically cleaned up"),
+ cipaction->olong);
+
+ return 0;
+}
diff --git a/src/main/verify.c b/src/main/verify.c
new file mode 100644
index 0000000..4abef9f
--- /dev/null
+++ b/src/main/verify.c
@@ -0,0 +1,243 @@
+/*
+ * dpkg - main program for package management
+ * verify.c - verify package integrity
+ *
+ * Copyright © 2012-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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+#include <dpkg/buffer.h>
+
+#include "main.h"
+
+
+enum verify_result {
+ VERIFY_NONE,
+ VERIFY_PASS,
+ VERIFY_FAIL,
+};
+
+struct verify_checks {
+ int exists_errno;
+ enum verify_result exists;
+ enum verify_result mode;
+ enum verify_result md5sum;
+};
+
+typedef void verify_output_func(struct fsys_namenode *, struct verify_checks *);
+
+static int
+verify_result_rpm(enum verify_result result, int check)
+{
+ switch (result) {
+ case VERIFY_FAIL:
+ return check;
+ case VERIFY_PASS:
+ return '.';
+ case VERIFY_NONE:
+ default:
+ return '?';
+ }
+}
+
+static void
+verify_output_rpm(struct fsys_namenode *namenode, struct verify_checks *checks)
+{
+ char result[9];
+ char *error = NULL;
+ int attr;
+
+ memset(result, '?', sizeof(result));
+
+ if (checks->exists == VERIFY_FAIL) {
+ memcpy(result, "missing ", sizeof(result));
+ if (checks->exists_errno != ENOENT)
+ m_asprintf(&error, " (%s)", strerror(checks->exists_errno));
+ } else {
+ result[1] = verify_result_rpm(checks->mode, 'M');
+ result[2] = verify_result_rpm(checks->md5sum, '5');
+ }
+
+ if (namenode->flags & FNNF_OLD_CONFF)
+ attr = 'c';
+ else
+ attr = ' ';
+
+ printf("%.9s %c %s%s\n", result, attr, namenode->name, error ? error : "");
+
+ free(error);
+}
+
+static verify_output_func *verify_output = verify_output_rpm;
+
+bool
+verify_set_output(const char *name)
+{
+ if (strcmp(name, "rpm") == 0)
+ verify_output = verify_output_rpm;
+ else
+ return false;
+
+ return true;
+}
+
+static int
+verify_digest(const char *filename, struct fsys_namenode *fnn,
+ struct verify_checks *checks)
+{
+ struct dpkg_error err;
+ static int fd;
+ char hash[MD5HASHLEN + 1];
+
+ fd = open(filename, O_RDONLY);
+
+ if (fd >= 0) {
+ push_cleanup(cu_closefd, ehflag_bombout, 1, &fd);
+ if (fd_md5(fd, hash, -1, &err) < 0)
+ ohshit(_("cannot compute MD5 digest for file '%s': %s"),
+ filename, err.str);
+ pop_cleanup(ehflag_normaltidy); /* fd = open(cdr.buf) */
+ close(fd);
+
+ if (strcmp(hash, fnn->newhash) == 0) {
+ checks->md5sum = VERIFY_PASS;
+ return 0;
+ } else {
+ checks->md5sum = VERIFY_FAIL;
+ }
+ } else {
+ checks->md5sum = VERIFY_NONE;
+ }
+
+ return -1;
+}
+
+static int
+verify_file(const char *filename, struct fsys_namenode *fnn,
+ struct pkginfo *pkg, struct verify_checks *checks)
+{
+ struct stat st;
+ int failures = 0;
+
+ if (lstat(filename, &st) < 0) {
+ checks->exists_errno = errno;
+ checks->exists = VERIFY_FAIL;
+ return 1;
+ }
+ checks->exists = VERIFY_PASS;
+
+ if (fnn->newhash == NULL && fnn->oldhash != NULL)
+ fnn->newhash = fnn->oldhash;
+
+ if (fnn->newhash != NULL) {
+ /* Mode check heuristic: If we know its digest, the pathname
+ * must be a regular file. */
+ if (!S_ISREG(st.st_mode)) {
+ checks->mode = VERIFY_FAIL;
+ failures++;
+ }
+
+ if (verify_digest(filename, fnn, checks) < 0)
+ failures++;
+ }
+
+ return failures;
+}
+
+static void
+verify_package(struct pkginfo *pkg)
+{
+ struct fsys_namenode_list *file;
+ struct varbuf filename = VARBUF_INIT;
+
+ ensure_packagefiles_available(pkg);
+ parse_filehash(pkg, &pkg->installed);
+ pkg_conffiles_mark_old(pkg);
+
+ for (file = pkg->files; file; file = file->next) {
+ struct verify_checks checks;
+ struct fsys_namenode *fnn;
+
+ fnn = namenodetouse(file->namenode, pkg, &pkg->installed);
+
+ varbuf_reset(&filename);
+ varbuf_add_str(&filename, dpkg_fsys_get_dir());
+ varbuf_add_str(&filename, fnn->name);
+ varbuf_end_str(&filename);
+
+ memset(&checks, 0, sizeof(checks));
+
+ if (verify_file(filename.buf, fnn, pkg, &checks) > 0)
+ verify_output(fnn, &checks);
+ }
+
+ varbuf_destroy(&filename);
+}
+
+int
+verify(const char *const *argv)
+{
+ struct pkginfo *pkg;
+ int rc = 0;
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_diversions();
+
+ if (!*argv) {
+ struct pkg_hash_iter *iter;
+
+ iter = pkg_hash_iter_new();
+ while ((pkg = pkg_hash_iter_next_pkg(iter)))
+ verify_package(pkg);
+ pkg_hash_iter_free(iter);
+ } else {
+ const char *thisarg;
+
+ while ((thisarg = *argv++)) {
+ pkg = dpkg_options_parse_pkgname(cipaction, thisarg);
+ if (pkg->status == PKG_STAT_NOTINSTALLED) {
+ notice(_("package '%s' is not installed"),
+ pkg_name(pkg, pnaw_nonambig));
+ rc = 1;
+ continue;
+ }
+
+ verify_package(pkg);
+ }
+ }
+
+ modstatdb_shutdown();
+
+ m_output(stdout, _("<standard output>"));
+
+ return rc;
+}
diff --git a/src/query/main.c b/src/query/main.c
new file mode 100644
index 0000000..5f19679
--- /dev/null
+++ b/src/query/main.c
@@ -0,0 +1,881 @@
+/*
+ * dpkg-query - program for query the dpkg database
+ * querycmd.c - status enquiry and listing options
+ *
+ * Copyright © 1995,1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
+ * Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <hertzog@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>
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.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/debug.h>
+#include <dpkg/pkg-array.h>
+#include <dpkg/pkg-spec.h>
+#include <dpkg/pkg-format.h>
+#include <dpkg/pkg-show.h>
+#include <dpkg/string.h>
+#include <dpkg/path.h>
+#include <dpkg/file.h>
+#include <dpkg/pager.h>
+#include <dpkg/options.h>
+#include <dpkg/db-ctrl.h>
+#include <dpkg/db-fsys.h>
+
+#include "actions.h"
+
+static const char *showformat = "${binary:Package}\t${Version}\n";
+
+static int opt_loadavail = 0;
+
+static int
+pkg_array_match_patterns(struct pkg_array *array,
+ pkg_array_visitor_func *pkg_visitor, void *pkg_data,
+ const char *const *argv)
+{
+ int argc, i, ip, *found;
+ int rc = 0;
+ struct pkg_spec *ps;
+
+ for (argc = 0; argv[argc]; argc++);
+ found = m_calloc(argc, sizeof(int));
+
+ ps = m_malloc(sizeof(*ps) * argc);
+ for (ip = 0; ip < argc; ip++) {
+ pkg_spec_init(&ps[ip], PKG_SPEC_PATTERNS | PKG_SPEC_ARCH_WILDCARD);
+ pkg_spec_parse(&ps[ip], argv[ip]);
+ }
+
+ for (i = 0; i < array->n_pkgs; i++) {
+ struct pkginfo *pkg;
+ bool pkg_found = false;
+
+ pkg = array->pkgs[i];
+ for (ip = 0; ip < argc; ip++) {
+ if (pkg_spec_match_pkg(&ps[ip], pkg, &pkg->installed)) {
+ pkg_found = true;
+ found[ip]++;
+ }
+ }
+ if (!pkg_found)
+ array->pkgs[i] = NULL;
+ }
+
+ pkg_array_foreach(array, pkg_visitor, pkg_data);
+
+ for (ip = 0; ip < argc; ip++) {
+ if (!found[ip]) {
+ notice(_("no packages found matching %s"), argv[ip]);
+ rc++;
+ }
+ pkg_spec_destroy(&ps[ip]);
+ }
+
+ free(ps);
+ free(found);
+
+ return rc;
+}
+
+struct list_format {
+ bool head;
+ int nw;
+ int vw;
+ int aw;
+ int dw;
+};
+
+static void
+list_format_init(struct list_format *fmt, struct pkg_array *array)
+{
+ int i;
+
+ if (fmt->nw != 0)
+ return;
+
+ fmt->nw = 14;
+ fmt->vw = 12;
+ fmt->aw = 12;
+ fmt->dw = 33;
+
+ for (i = 0; i < array->n_pkgs; i++) {
+ int plen, vlen, alen, dlen;
+
+ if (array->pkgs[i] == NULL)
+ continue;
+
+ plen = str_width(pkg_name(array->pkgs[i], pnaw_nonambig));
+ vlen = str_width(versiondescribe(&array->pkgs[i]->installed.version,
+ vdew_nonambig));
+ alen = str_width(dpkg_arch_describe(array->pkgs[i]->installed.arch));
+ pkg_synopsis(array->pkgs[i], &dlen);
+
+ if (plen > fmt->nw)
+ fmt->nw = plen;
+ if (vlen > fmt->vw)
+ fmt->vw = vlen;
+ if (alen > fmt->aw)
+ fmt->aw = alen;
+ if (dlen > fmt->dw)
+ fmt->dw = dlen;
+ }
+}
+
+static void
+list_format_print(struct list_format *fmt,
+ int c_want, int c_status, int c_eflag,
+ const char *name, const char *version, const char *arch,
+ const char *desc, int desc_len)
+{
+ struct str_crop_info ns, vs, as, ds;
+
+ str_gen_crop(name, fmt->nw, &ns);
+ str_gen_crop(version, fmt->vw, &vs);
+ str_gen_crop(arch, fmt->aw, &as);
+ str_gen_crop(desc, desc_len, &ds);
+
+ printf("%c%c%c %-*.*s %-*.*s %-*.*s %.*s\n", c_want, c_status, c_eflag,
+ ns.max_bytes, ns.str_bytes, name,
+ vs.max_bytes, vs.str_bytes, version,
+ as.max_bytes, as.str_bytes, arch,
+ ds.str_bytes, desc);
+}
+
+static void
+list_format_print_header(struct list_format *fmt)
+{
+ int l;
+
+ if (fmt->head)
+ return;
+
+ /* TRANSLATORS: This is the header that appears on 'dpkg-query -l'. The
+ * string should remain under 80 characters. The uppercase letters in
+ * the state values denote the abbreviated letter that will appear on
+ * the first three columns, which should ideally match the English one
+ * (e.g. Remove → supRimeix), see dpkg-query(1) for further details. The
+ * translated message can use additional lines if needed. */
+ fputs(_("\
+Desired=Unknown/Install/Remove/Purge/Hold\n\
+| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend\n\
+|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)\n"), stdout);
+ list_format_print(fmt, '|', '|', '/', _("Name"), _("Version"),
+ _("Architecture"), _("Description"), fmt->dw);
+
+ /* Status */
+ printf("+++-");
+
+ /* Package name. */
+ for (l = 0; l < fmt->nw; l++)
+ printf("=");
+ printf("-");
+
+ /* Version. */
+ for (l = 0; l < fmt->vw; l++)
+ printf("=");
+ printf("-");
+
+ /* Architecture. */
+ for (l = 0; l < fmt->aw; l++)
+ printf("=");
+ printf("-");
+
+ /* Description. */
+ for (l = 0; l < fmt->dw; l++)
+ printf("=");
+ printf("\n");
+
+ fmt->head = true;
+}
+
+static void
+pkg_array_list_item(struct pkg_array *array, struct pkginfo *pkg, void *pkg_data)
+{
+ struct list_format *fmt = pkg_data;
+ int l;
+ const char *pdesc;
+
+ list_format_init(fmt, array);
+ list_format_print_header(fmt);
+
+ pdesc = pkg_synopsis(pkg, &l);
+ l = min(l, fmt->dw);
+
+ list_format_print(fmt,
+ pkg_abbrev_want(pkg),
+ pkg_abbrev_status(pkg),
+ pkg_abbrev_eflag(pkg),
+ pkg_name(pkg, pnaw_nonambig),
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ dpkg_arch_describe(pkg->installed.arch),
+ pdesc, l);
+}
+
+static int
+listpackages(const char *const *argv)
+{
+ struct pkg_array array;
+ struct pkginfo *pkg;
+ int i;
+ int rc = 0;
+ struct list_format fmt;
+ struct pager *pager;
+
+ if (!opt_loadavail)
+ modstatdb_open(msdbrw_readonly);
+ else
+ modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
+
+ pkg_array_init_from_hash(&array);
+ pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
+
+ memset(&fmt, 0, sizeof(fmt));
+
+ pager = pager_spawn(_("showing package list on pager"));
+
+ if (!*argv) {
+ for (i = 0; i < array.n_pkgs; i++) {
+ pkg = array.pkgs[i];
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ array.pkgs[i] = NULL;
+ }
+
+ pkg_array_foreach(&array, pkg_array_list_item, &fmt);
+ } else {
+ rc = pkg_array_match_patterns(&array, pkg_array_list_item, &fmt, argv);
+ }
+
+ m_output(stdout, _("<standard output>"));
+ m_output(stderr, _("<standard error>"));
+
+ pager_reap(pager);
+
+ pkg_array_destroy(&array);
+ modstatdb_shutdown();
+
+ return rc;
+}
+
+static int
+searchoutput(struct fsys_namenode *namenode)
+{
+ struct fsys_node_pkgs_iter *iter;
+ struct pkginfo *pkg_owner;
+ int found;
+
+ if (namenode->divert) {
+ const char *name_from = namenode->divert->camefrom ?
+ namenode->divert->camefrom->name : namenode->name;
+ const char *name_to = namenode->divert->useinstead ?
+ namenode->divert->useinstead->name : namenode->name;
+
+ if (namenode->divert->pkgset) {
+ printf(_("diversion by %s from: %s\n"),
+ namenode->divert->pkgset->name, name_from);
+ printf(_("diversion by %s to: %s\n"),
+ namenode->divert->pkgset->name, name_to);
+ } else {
+ printf(_("local diversion from: %s\n"), name_from);
+ printf(_("local diversion to: %s\n"), name_to);
+ }
+ }
+ found= 0;
+
+ iter = fsys_node_pkgs_iter_new(namenode);
+ while ((pkg_owner = fsys_node_pkgs_iter_next(iter))) {
+ if (found)
+ fputs(", ", stdout);
+ fputs(pkg_name(pkg_owner, pnaw_nonambig), stdout);
+ found++;
+ }
+ fsys_node_pkgs_iter_free(iter);
+
+ if (found) printf(": %s\n",namenode->name);
+ return found + (namenode->divert ? 1 : 0);
+}
+
+static int
+searchfiles(const char *const *argv)
+{
+ struct fsys_namenode *namenode;
+ struct fsys_hash_iter *iter;
+ const char *thisarg;
+ int found;
+ int failures = 0;
+ struct varbuf path = VARBUF_INIT;
+ static struct varbuf vb;
+
+ if (!*argv)
+ badusage(_("--search needs at least one file name pattern argument"));
+
+ modstatdb_open(msdbrw_readonly);
+ ensure_allinstfiles_available_quiet();
+ ensure_diversions();
+
+ while ((thisarg = *argv++) != NULL) {
+ found= 0;
+
+ if (!strchr("*[?/",*thisarg)) {
+ varbuf_reset(&vb);
+ varbuf_add_char(&vb, '*');
+ varbuf_add_str(&vb, thisarg);
+ varbuf_add_char(&vb, '*');
+ varbuf_end_str(&vb);
+ thisarg= vb.buf;
+ }
+ if (!strpbrk(thisarg, "*[?\\")) {
+ /* Trim trailing ‘/’ and ‘/.’ from the argument if it is not
+ * a pattern, just a pathname. */
+ varbuf_reset(&path);
+ varbuf_add_str(&path, thisarg);
+ varbuf_end_str(&path);
+ varbuf_trunc(&path, path_trim_slash_slashdot(path.buf));
+
+ namenode = fsys_hash_find_node(path.buf, 0);
+ found += searchoutput(namenode);
+ } else {
+ iter = fsys_hash_iter_new();
+ while ((namenode = fsys_hash_iter_next(iter)) != NULL) {
+ if (fnmatch(thisarg,namenode->name,0)) continue;
+ found+= searchoutput(namenode);
+ }
+ fsys_hash_iter_free(iter);
+ }
+ if (!found) {
+ notice(_("no path found matching pattern %s"), thisarg);
+ failures++;
+ m_output(stderr, _("<standard error>"));
+ } else {
+ m_output(stdout, _("<standard output>"));
+ }
+ }
+ modstatdb_shutdown();
+
+ varbuf_destroy(&path);
+
+ return failures;
+}
+
+static int
+print_status(const char *const *argv)
+{
+ const char *thisarg;
+ struct pkginfo *pkg;
+ int failures = 0;
+
+ modstatdb_open(msdbrw_readonly);
+
+ if (!*argv) {
+ writedb_stanzas(stdout, _("<standard output>"), 0);
+ } else {
+ while ((thisarg = *argv++) != NULL) {
+ pkg = dpkg_options_parse_pkgname(cipaction, thisarg);
+
+ if (pkg->status == PKG_STAT_NOTINSTALLED &&
+ pkg->priority == PKG_PRIO_UNKNOWN &&
+ str_is_unset(pkg->section) &&
+ !pkg->archives &&
+ pkg->want == PKG_WANT_UNKNOWN &&
+ !pkg_is_informative(pkg, &pkg->installed)) {
+ notice(_("package '%s' is not installed and no information is available"),
+ pkg_name(pkg, pnaw_nonambig));
+ failures++;
+ } else {
+ write_stanza(stdout, _("<standard output>"), pkg, &pkg->installed);
+ }
+
+ if (*argv != NULL)
+ putchar('\n');
+ }
+ }
+
+ m_output(stdout, _("<standard output>"));
+ if (failures) {
+ fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files.\n"),
+ stderr);
+ m_output(stderr, _("<standard error>"));
+ }
+
+ modstatdb_shutdown();
+
+ return failures;
+}
+
+static int
+print_avail(const char *const *argv)
+{
+ const char *thisarg;
+ struct pkginfo *pkg;
+ int failures = 0;
+
+ modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
+
+ if (!*argv) {
+ writedb_stanzas(stdout, _("<standard output>"), wdb_dump_available);
+ } else {
+ while ((thisarg = *argv++) != NULL) {
+ pkg = dpkg_options_parse_pkgname(cipaction, thisarg);
+
+ if (!pkg_is_informative(pkg, &pkg->available)) {
+ notice(_("package '%s' is not available"),
+ pkgbin_name(pkg, &pkg->available, pnaw_nonambig));
+ failures++;
+ } else {
+ write_stanza(stdout, _("<standard output>"), pkg, &pkg->available);
+ }
+
+ if (*argv != NULL)
+ putchar('\n');
+ }
+ }
+
+ m_output(stdout, _("<standard output>"));
+ if (failures)
+ m_output(stderr, _("<standard error>"));
+
+ modstatdb_shutdown();
+
+ return failures;
+}
+
+static int
+list_files(const char *const *argv)
+{
+ const char *thisarg;
+ struct fsys_namenode_list *file;
+ struct pkginfo *pkg;
+ struct fsys_namenode *namenode;
+ int failures = 0;
+
+ if (!*argv)
+ badusage(_("--%s needs at least one package name argument"), cipaction->olong);
+
+ modstatdb_open(msdbrw_readonly);
+
+ while ((thisarg = *argv++) != NULL) {
+ pkg = dpkg_options_parse_pkgname(cipaction, thisarg);
+
+ switch (pkg->status) {
+ case PKG_STAT_NOTINSTALLED:
+ notice(_("package '%s' is not installed"),
+ pkg_name(pkg, pnaw_nonambig));
+ failures++;
+ break;
+ default:
+ ensure_packagefiles_available(pkg);
+ ensure_diversions();
+ file = pkg->files;
+ if (!file) {
+ printf(_("Package '%s' does not contain any files (!)\n"),
+ pkg_name(pkg, pnaw_nonambig));
+ } else {
+ while (file) {
+ namenode = file->namenode;
+ puts(namenode->name);
+ if (namenode->divert && !namenode->divert->camefrom) {
+ if (!namenode->divert->pkgset)
+ printf(_("locally diverted to: %s\n"),
+ namenode->divert->useinstead->name);
+ else if (pkg->set == namenode->divert->pkgset)
+ printf(_("package diverts others to: %s\n"),
+ namenode->divert->useinstead->name);
+ else
+ printf(_("diverted by %s to: %s\n"),
+ namenode->divert->pkgset->name,
+ namenode->divert->useinstead->name);
+ }
+ file = file->next;
+ }
+ }
+ break;
+ }
+
+ if (*argv != NULL)
+ putchar('\n');
+ }
+
+ m_output(stdout, _("<standard output>"));
+ if (failures) {
+ fputs(_("Use dpkg --contents (= dpkg-deb --contents) to list archive files contents.\n"),
+ stderr);
+ m_output(stderr, _("<standard error>"));
+ }
+
+ modstatdb_shutdown();
+
+ return failures;
+}
+
+static void
+pkg_array_load_db_fsys(struct pkg_array *array, struct pkginfo *pkg, void *pkg_data)
+{
+ ensure_packagefiles_available(pkg);
+}
+
+static void
+pkg_array_show_item(struct pkg_array *array, struct pkginfo *pkg, void *pkg_data)
+{
+ struct pkg_format_node *fmt = pkg_data;
+
+ pkg_format_show(fmt, pkg, &pkg->installed);
+}
+
+static int
+showpackages(const char *const *argv)
+{
+ struct dpkg_error err;
+ struct pkg_array array;
+ struct pkginfo *pkg;
+ struct pkg_format_node *fmt;
+ bool fmt_needs_db_fsys;
+ int i;
+ int rc = 0;
+
+ fmt = pkg_format_parse(showformat, &err);
+ if (!fmt) {
+ notice(_("error in show format: %s"), err.str);
+ dpkg_error_destroy(&err);
+ rc++;
+ return rc;
+ }
+
+ fmt_needs_db_fsys = pkg_format_needs_db_fsys(fmt);
+
+ if (!opt_loadavail)
+ modstatdb_open(msdbrw_readonly);
+ else
+ modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
+
+ pkg_array_init_from_hash(&array);
+ pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
+
+ if (!*argv) {
+ if (fmt_needs_db_fsys)
+ ensure_allinstfiles_available_quiet();
+ for (i = 0; i < array.n_pkgs; i++) {
+ pkg = array.pkgs[i];
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ continue;
+ pkg_format_show(fmt, pkg, &pkg->installed);
+ }
+ } else {
+ if (fmt_needs_db_fsys)
+ pkg_array_foreach(&array, pkg_array_load_db_fsys, NULL);
+ rc = pkg_array_match_patterns(&array, pkg_array_show_item, fmt, argv);
+ }
+
+ m_output(stdout, _("<standard output>"));
+ m_output(stderr, _("<standard error>"));
+
+ pkg_array_destroy(&array);
+ pkg_format_free(fmt);
+ modstatdb_shutdown();
+
+ return rc;
+}
+
+static bool
+pkg_infodb_is_internal(const char *filetype)
+{
+ /* Do not expose internal database files. */
+ if (strcmp(filetype, LISTFILE) == 0 ||
+ strcmp(filetype, CONFFILESFILE) == 0)
+ return true;
+
+ if (strlen(filetype) > MAXCONTROLFILENAME)
+ return true;
+
+ return false;
+}
+
+static void
+pkg_infodb_check_filetype(const char *filetype)
+{
+ const char *c;
+
+ /* Validate control file name for sanity. */
+ for (c = "/."; *c; c++)
+ if (strchr(filetype, *c))
+ badusage(_("control file contains %c"), *c);
+}
+
+static void
+pkg_infodb_print_filename(const char *filename, const char *filetype)
+{
+ if (pkg_infodb_is_internal(filetype))
+ return;
+
+ printf("%s\n", filename);
+}
+
+static void
+pkg_infodb_print_filetype(const char *filename, const char *filetype)
+{
+ if (pkg_infodb_is_internal(filetype))
+ return;
+
+ printf("%s\n", filetype);
+}
+
+static void
+control_path_file(struct pkginfo *pkg, const char *control_file)
+{
+ const char *control_pathname;
+ struct stat st;
+
+ control_pathname = pkg_infodb_get_file(pkg, &pkg->installed, control_file);
+ if (stat(control_pathname, &st) < 0)
+ return;
+ if (!S_ISREG(st.st_mode))
+ return;
+
+ pkg_infodb_print_filename(control_pathname, control_file);
+}
+
+static int
+control_path(const char *const *argv)
+{
+ struct pkginfo *pkg;
+ const char *pkgname;
+ const char *control_file;
+
+ pkgname = *argv++;
+ if (!pkgname)
+ badusage(_("--%s needs at least one package name argument"),
+ cipaction->olong);
+
+ control_file = *argv++;
+ if (control_file && *argv)
+ badusage(_("--%s takes at most two arguments"), cipaction->olong);
+
+ if (control_file)
+ pkg_infodb_check_filetype(control_file);
+
+ modstatdb_open(msdbrw_readonly);
+
+ pkg = dpkg_options_parse_pkgname(cipaction, pkgname);
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ ohshit(_("package '%s' is not installed"),
+ pkg_name(pkg, pnaw_nonambig));
+
+ if (control_file)
+ control_path_file(pkg, control_file);
+ else
+ pkg_infodb_foreach(pkg, &pkg->installed, pkg_infodb_print_filename);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static int
+control_list(const char *const *argv)
+{
+ struct pkginfo *pkg;
+ const char *pkgname;
+
+ pkgname = *argv++;
+ if (!pkgname || *argv)
+ badusage(_("--%s takes one package name argument"), cipaction->olong);
+
+ modstatdb_open(msdbrw_readonly);
+
+ pkg = dpkg_options_parse_pkgname(cipaction, pkgname);
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ ohshit(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig));
+
+ pkg_infodb_foreach(pkg, &pkg->installed, pkg_infodb_print_filetype);
+
+ modstatdb_shutdown();
+
+ return 0;
+}
+
+static int
+control_show(const char *const *argv)
+{
+ struct pkginfo *pkg;
+ const char *pkgname;
+ const char *filename;
+ const char *control_file;
+
+ pkgname = *argv++;
+ if (!pkgname || !*argv)
+ badusage(_("--%s takes exactly two arguments"),
+ cipaction->olong);
+
+ control_file = *argv++;
+ if (!control_file || *argv)
+ badusage(_("--%s takes exactly two arguments"), cipaction->olong);
+
+ pkg_infodb_check_filetype(control_file);
+
+ modstatdb_open(msdbrw_readonly);
+
+ pkg = dpkg_options_parse_pkgname(cipaction, pkgname);
+ if (pkg->status == PKG_STAT_NOTINSTALLED)
+ ohshit(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig));
+
+ if (pkg_infodb_has_file(pkg, &pkg->installed, control_file))
+ filename = pkg_infodb_get_file(pkg, &pkg->installed, control_file);
+ else
+ ohshit(_("control file '%s' does not exist"), control_file);
+
+ modstatdb_shutdown();
+
+ file_show(filename);
+
+ return 0;
+}
+
+static void
+set_no_pager(const struct cmdinfo *ci, const char *value)
+{
+ pager_enable(false);
+}
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian %s package management program query tool version %s.\n"),
+ DPKGQUERY, PACKAGE_RELEASE);
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option>...] <command>\n"
+"\n"), DPKGQUERY);
+
+ printf(_(
+"Commands:\n"
+" -s, --status [<package>...] Display package status details.\n"
+" -p, --print-avail [<package>...] Display available version details.\n"
+" -L, --listfiles <package>... List files 'owned' by package(s).\n"
+" -l, --list [<pattern>...] List packages concisely.\n"
+" -W, --show [<pattern>...] Show information on package(s).\n"
+" -S, --search <pattern>... Find package(s) owning file(s).\n"
+" --control-list <package> Print the package control file list.\n"
+" --control-show <package> <file>\n"
+" Show the package control file.\n"
+" -c, --control-path <package> [<file>]\n"
+" Print path for package control file.\n"
+"\n"));
+
+ printf(_(
+" -?, --help Show this help message.\n"
+" --version Show the version.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --admindir=<directory> Use <directory> instead of %s.\n"
+" --root=<directory> Use <directory> instead of %s.\n"
+" --load-avail Use available file on --show and --list.\n"
+" --no-pager Disables the use of any pager.\n"
+" -f|--showformat=<format> Use alternative format for --show.\n"
+"\n"), ADMINDIR, "/");
+
+ printf(_(
+"Format syntax:\n"
+" A format is a string that will be output for each package. The format\n"
+" can include the standard escape sequences \\n (newline), \\r (carriage\n"
+" return) or \\\\ (plain backslash). Package information can be included\n"
+" by inserting variable references to package fields using the ${var[;width]}\n"
+" syntax. Fields will be right-aligned unless the width is negative in which\n"
+" case left alignment will be used.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static const char printforhelp[] = N_(
+"Use --help for help about querying packages.");
+
+/* This table has both the action entries in it and the normal options.
+ * The action entries are made with the ACTION macro, as they all
+ * have a very similar structure. */
+static const struct cmdinfo cmdinfos[]= {
+ ACTION( "listfiles", 'L', act_listfiles, list_files ),
+ ACTION( "status", 's', act_status, print_status ),
+ ACTION( "print-avail", 'p', act_printavail, print_avail ),
+ ACTION( "list", 'l', act_listpackages, listpackages ),
+ ACTION( "search", 'S', act_searchfiles, searchfiles ),
+ ACTION( "show", 'W', act_listpackages, showpackages ),
+ ACTION( "control-path", 'c', act_controlpath, control_path ),
+ ACTION( "control-list", 0, act_controllist, control_list ),
+ ACTION( "control-show", 0, act_controlshow, control_show ),
+ ACTION( "help", '?', act_help, usage ),
+ ACTION( "version", 0, act_version, printversion ),
+
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "load-avail", 0, 0, &opt_loadavail, NULL, NULL, 1 },
+ { "showformat", 'f', 1, NULL, &showformat, NULL },
+ { "no-pager", 0, 0, NULL, NULL, set_no_pager },
+ { NULL, 0, 0, NULL, NULL, NULL }
+};
+
+int main(int argc, const char *const *argv) {
+ int ret;
+
+ dpkg_set_report_piped_mode(_IOFBF);
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init("dpkg-query");
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ if (!cipaction) badusage(_("need an action option"));
+
+ ret = cipaction->action(argv);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return !!ret;
+}
diff --git a/src/sh/dpkg-error.sh b/src/sh/dpkg-error.sh
new file mode 100644
index 0000000..b7f968e
--- /dev/null
+++ b/src/sh/dpkg-error.sh
@@ -0,0 +1,93 @@
+#
+# Copyright © 2010 Raphaël Hertzog <hertzog@debian.org>
+# Copyright © 2011-2015 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/>.
+#
+# shellcheck shell=sh
+
+# Standard ANSI colors and attributes.
+COLOR_NORMAL=''
+COLOR_RESET=''
+COLOR_BOLD=''
+COLOR_BLACK=''
+COLOR_RED=''
+COLOR_GREEN=''
+COLOR_YELLOW=''
+COLOR_BLUE=''
+COLOR_MAGENTA=''
+COLOR_CYAN=''
+COLOR_WHITE=''
+COLOR_BOLD_BLACK=''
+COLOR_BOLD_RED=''
+COLOR_BOLD_GREEN=''
+COLOR_BOLD_YELLOW=''
+COLOR_BOLD_BLUE=''
+COLOR_BOLD_MAGENTA=''
+COLOR_BOLD_CYAN=''
+COLOR_BOLD_WHITE=''
+
+setup_colors()
+{
+ : "${DPKG_COLORS=auto}"
+
+ case "$DPKG_COLORS" in
+ auto)
+ if [ -t 1 ]; then
+ USE_COLORS=yes
+ else
+ USE_COLORS=no
+ fi
+ ;;
+ always)
+ USE_COLORS=yes
+ ;;
+ *)
+ USE_COLORS=no
+ ;;
+ esac
+
+ if [ $USE_COLORS = yes ]; then
+ COLOR_PROG="$COLOR_BOLD"
+ COLOR_INFO="$COLOR_GREEN"
+ COLOR_NOTICE="$COLOR_YELLOW"
+ COLOR_WARN="$COLOR_BOLD_YELLOW"
+ COLOR_ERROR="$COLOR_BOLD_RED"
+ else
+ COLOR_RESET=""
+ fi
+ FMT_PROG="$COLOR_PROG$PROGNAME$COLOR_RESET"
+}
+
+debug() {
+ if [ -n "$DPKG_DEBUG" ]; then
+ echo "DEBUG: $FMT_PROG: $*" >&2
+ fi
+}
+
+error() {
+ echo "$FMT_PROG: ${COLOR_ERROR}error${COLOR_RESET}: $*" >&2
+ exit 1
+}
+
+warning() {
+ echo "$FMT_PROG: ${COLOR_WARN}warning${COLOR_RESET}: $*" >&2
+}
+
+badusage() {
+ echo "$FMT_PROG: ${COLOR_ERROR}error${COLOR_RESET}: $1" >&2
+ echo >&2
+ echo "Use '$PROGNAME --help' for program usage information." >&2
+ exit 1
+}
diff --git a/src/split/dpkg-split.h b/src/split/dpkg-split.h
new file mode 100644
index 0000000..f53e0c5
--- /dev/null
+++ b/src/split/dpkg-split.h
@@ -0,0 +1,84 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * dpkg-split.h - external definitions for this program
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2008-2012 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 DPKG_SPLIT_H
+#define DPKG_SPLIT_H
+
+#include <dpkg/ar.h>
+#include <dpkg/deb-version.h>
+
+action_func do_split;
+action_func do_join;
+action_func do_info;
+action_func do_auto;
+action_func do_queue;
+action_func do_discard;
+
+struct partinfo {
+ struct deb_version fmtversion;
+ const char *filename;
+ const char *package;
+ const char *version;
+ const char *arch;
+ const char *md5sum;
+ off_t orglength;
+ int thispartn, maxpartn;
+ off_t maxpartlen;
+ off_t thispartoffset;
+ off_t thispartlen;
+ /** Size of header in part file. */
+ off_t headerlen;
+ off_t filesize;
+};
+
+struct partqueue {
+ struct partqueue *nextinqueue;
+
+ /** Only fields filename, md5sum, maxpartlen, thispartn, maxpartn
+ * are valid; the rest are NULL. If the file is not named correctly
+ * to be a part file md5sum is NULL too and the numbers are zero. */
+ struct partinfo info;
+};
+
+extern off_t opt_maxpartsize;
+extern const char *opt_depotdir;
+extern const char *opt_outputfile;
+extern int opt_npquiet;
+extern int opt_msdos;
+
+void read_fail(int rc, const char *filename, const char *what) DPKG_ATTR_NORET;
+void print_info(const struct partinfo *pi);
+struct partinfo *read_info(struct dpkg_ar *ar, struct partinfo *ir);
+
+void reassemble(struct partinfo **partlist, const char *outputfile);
+void mustgetpartinfo(const char *filename, struct partinfo *ri);
+void addtopartlist(struct partinfo**, struct partinfo*, struct partinfo *refi);
+
+#define SPLITVERSION "2.1"
+
+#define PARTSDIR "parts"
+
+#define PARTMAGIC "debian-split"
+#define HEADERALLOWANCE 1024
+
+#define SPLITPARTDEFMAX (450 * 1024)
+
+#endif /* DPKG_SPLIT_H */
diff --git a/src/split/info.c b/src/split/info.c
new file mode 100644
index 0000000..73fbd69
--- /dev/null
+++ b/src/split/info.c
@@ -0,0 +1,291 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * info.c - information about split archives
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2008-2012 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/stat.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <stdint.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/fdio.h>
+#include <dpkg/ar.h>
+#include <dpkg/options.h>
+
+#include "dpkg-split.h"
+
+static intmax_t
+parse_intmax(const char *value, const char *fn, const char *what)
+{
+ intmax_t r;
+ char *endp;
+
+ errno = 0;
+ r = strtoimax(value, &endp, 10);
+ if (value == endp || *endp)
+ ohshit(_("file '%.250s' is corrupt - bad digit (code %d) in %s"),
+ fn, *endp, what);
+ if (r < 0 || errno == ERANGE)
+ ohshit(_("file '%s' is corrupt; out of range integer in %s"), fn, what);
+ return r;
+}
+
+static char *nextline(char **ripp, const char *fn, const char *what) {
+ char *newline, *rip;
+
+ rip= *ripp;
+ if (!rip)
+ ohshit(_("file '%.250s' is corrupt - %.250s missing"), fn, what);
+ newline= strchr(rip,'\n');
+ if (!newline)
+ ohshit(_("file '%.250s' is corrupt - missing newline after %.250s"),
+ fn, what);
+ *ripp= newline+1;
+
+ str_rtrim_spaces(rip, newline);
+
+ return rip;
+}
+
+/**
+ * Read a deb-split part archive.
+ *
+ * @return Part info (nfmalloc'd) if was an archive part and we read it,
+ * NULL if it wasn't.
+ */
+struct partinfo *
+read_info(struct dpkg_ar *ar, struct partinfo *ir)
+{
+ static char *readinfobuf= NULL;
+ static size_t readinfobuflen= 0;
+
+ size_t thisilen;
+ intmax_t templong;
+ char magicbuf[sizeof(DPKG_AR_MAGIC) - 1], *rip, *partnums, *slash;
+ const char *err;
+ struct dpkg_ar_hdr arh;
+ ssize_t rc;
+
+ rc = fd_read(ar->fd, magicbuf, sizeof(magicbuf));
+ if (rc != sizeof(magicbuf)) {
+ if (rc < 0)
+ ohshite(_("error reading %.250s"), ar->name);
+ else
+ return NULL;
+ }
+ if (memcmp(magicbuf, DPKG_AR_MAGIC, sizeof(magicbuf)))
+ return NULL;
+
+ rc = fd_read(ar->fd, &arh, sizeof(arh));
+ if (rc != sizeof(arh))
+ read_fail(rc, ar->name, "ar header");
+
+ dpkg_ar_normalize_name(&arh);
+
+ if (strncmp(arh.ar_name, PARTMAGIC, sizeof(arh.ar_name)) != 0)
+ return NULL;
+ if (dpkg_ar_member_is_illegal(&arh))
+ ohshit(_("file '%.250s' is corrupt - bad magic at end of first header"),
+ ar->name);
+ thisilen = dpkg_ar_member_get_size(ar, &arh);
+ if (thisilen >= readinfobuflen) {
+ readinfobuflen = thisilen + 2;
+ readinfobuf= m_realloc(readinfobuf,readinfobuflen);
+ }
+ rc = fd_read(ar->fd, readinfobuf, thisilen + (thisilen & 1));
+ if (rc != (ssize_t)(thisilen + (thisilen & 1)))
+ read_fail(rc, ar->name, "reading header member");
+ if (thisilen & 1) {
+ int c = readinfobuf[thisilen];
+
+ if (c != '\n')
+ ohshit(_("file '%.250s' is corrupt - bad padding character (code %d)"),
+ ar->name, c);
+ }
+ readinfobuf[thisilen] = '\0';
+ if (memchr(readinfobuf,0,thisilen))
+ ohshit(_("file '%.250s' is corrupt - nulls in info section"), ar->name);
+
+ ir->filename = ar->name;
+
+ rip= readinfobuf;
+ err = deb_version_parse(&ir->fmtversion,
+ nextline(&rip, ar->name, _("format version number")));
+ if (err)
+ ohshit(_("file '%.250s' has invalid format version: %s"), ar->name, err);
+ if (ir->fmtversion.major != 2)
+ ohshit(_("file '%.250s' is format version %d.%d; get a newer dpkg-split"),
+ ar->name, ir->fmtversion.major, ir->fmtversion.minor);
+
+ ir->package = nfstrsave(nextline(&rip, ar->name, _("package name")));
+ ir->version = nfstrsave(nextline(&rip, ar->name, _("package version number")));
+ ir->md5sum = nfstrsave(nextline(&rip, ar->name, _("package file MD5 checksum")));
+ if (strlen(ir->md5sum) != MD5HASHLEN ||
+ strspn(ir->md5sum, "0123456789abcdef") != MD5HASHLEN)
+ ohshit(_("file '%.250s' is corrupt - bad MD5 checksum '%.250s'"),
+ ar->name, ir->md5sum);
+
+ ir->orglength = parse_intmax(nextline(&rip, ar->name, _("archive total size")),
+ ar->name, _("archive total size"));
+ ir->maxpartlen = parse_intmax(nextline(&rip, ar->name, _("archive part offset")),
+ ar->name, _("archive part offset"));
+
+ partnums = nextline(&rip, ar->name, _("archive part numbers"));
+ slash= strchr(partnums,'/');
+ if (!slash)
+ ohshit(_("file '%.250s' is corrupt - no slash between archive part numbers"), ar->name);
+ *slash++ = '\0';
+
+ templong = parse_intmax(slash, ar->name, _("number of archive parts"));
+ if (templong <= 0 || templong > INT_MAX)
+ ohshit(_("file '%.250s' is corrupt - bad number of archive parts"), ar->name);
+ ir->maxpartn= templong;
+ templong = parse_intmax(partnums, ar->name, _("archive parts number"));
+ if (templong <= 0 || templong > ir->maxpartn)
+ ohshit(_("file '%.250s' is corrupt - bad archive part number"), ar->name);
+ ir->thispartn= templong;
+
+ /* If the package was created with dpkg 1.16.1 or later it will include
+ * the architecture. */
+ if (*rip != '\0')
+ ir->arch = nfstrsave(nextline(&rip, ar->name, _("package architecture")));
+ else
+ ir->arch = NULL;
+
+ rc = fd_read(ar->fd, &arh, sizeof(arh));
+ if (rc != sizeof(arh))
+ read_fail(rc, ar->name, "reading data part member ar header");
+
+ dpkg_ar_normalize_name(&arh);
+
+ if (dpkg_ar_member_is_illegal(&arh))
+ ohshit(_("file '%.250s' is corrupt - bad magic at end of second header"),
+ ar->name);
+ if (strncmp(arh.ar_name,"data",4))
+ ohshit(_("file '%.250s' is corrupt - second member is not data member"),
+ ar->name);
+
+ ir->thispartlen = dpkg_ar_member_get_size(ar, &arh);
+ ir->thispartoffset= (ir->thispartn-1)*ir->maxpartlen;
+
+ if (ir->maxpartn != (ir->orglength+ir->maxpartlen-1)/ir->maxpartlen)
+ ohshit(_("file '%.250s' is corrupt - wrong number of parts for quoted sizes"),
+ ar->name);
+ if (ir->thispartlen !=
+ (ir->thispartn == ir->maxpartn
+ ? ir->orglength - ir->thispartoffset : ir->maxpartlen))
+ ohshit(_("file '%.250s' is corrupt - size is wrong for quoted part number"),
+ ar->name);
+
+ ir->filesize = (strlen(DPKG_AR_MAGIC) +
+ sizeof(arh) + thisilen + (thisilen & 1) +
+ sizeof(arh) + ir->thispartlen + (ir->thispartlen & 1));
+
+ if (S_ISREG(ar->mode)) {
+ /* Don't do this check if it's coming from a pipe or something. It's
+ * only an extra sanity check anyway. */
+ if (ar->size < ir->filesize)
+ ohshit(_("file '%.250s' is corrupt - too short"), ar->name);
+ }
+
+ ir->headerlen = strlen(DPKG_AR_MAGIC) +
+ sizeof(arh) + thisilen + (thisilen & 1) + sizeof(arh);
+
+ return ir;
+}
+
+void mustgetpartinfo(const char *filename, struct partinfo *ri) {
+ struct dpkg_ar *part;
+
+ part = dpkg_ar_open(filename);
+ if (!part)
+ ohshite(_("cannot open archive part file '%.250s'"), filename);
+ if (!read_info(part, ri))
+ ohshite(_("file '%.250s' is not an archive part"), filename);
+ dpkg_ar_close(part);
+}
+
+void print_info(const struct partinfo *pi) {
+ printf(_("%s:\n"
+ " Part format version: %d.%d\n"
+ " Part of package: %s\n"
+ " ... version: %s\n"
+ " ... architecture: %s\n"
+ " ... MD5 checksum: %s\n"
+ " ... length: %jd bytes\n"
+ " ... split every: %jd bytes\n"
+ " Part number: %d/%d\n"
+ " Part length: %jd bytes\n"
+ " Part offset: %jd bytes\n"
+ " Part file size (used portion): %jd bytes\n\n"),
+ pi->filename,
+ pi->fmtversion.major, pi->fmtversion.minor,
+ pi->package,
+ pi->version,
+ pi->arch ? pi->arch : C_("architecture", "<unknown>"),
+ pi->md5sum,
+ (intmax_t)pi->orglength,
+ (intmax_t)pi->maxpartlen,
+ pi->thispartn,
+ pi->maxpartn,
+ (intmax_t)pi->thispartlen,
+ (intmax_t)pi->thispartoffset,
+ (intmax_t)pi->filesize);
+}
+
+int
+do_info(const char *const *argv)
+{
+ const char *thisarg;
+ struct partinfo *pi, ps;
+ struct dpkg_ar *part;
+
+ if (!*argv)
+ badusage(_("--%s requires one or more part file arguments"),
+ cipaction->olong);
+
+ while ((thisarg= *argv++)) {
+ part = dpkg_ar_open(thisarg);
+ if (!part)
+ ohshite(_("cannot open archive part file '%.250s'"), thisarg);
+ pi = read_info(part, &ps);
+ dpkg_ar_close(part);
+ if (pi) {
+ print_info(pi);
+ } else {
+ printf(_("file '%s' is not an archive part\n"), thisarg);
+ }
+ m_output(stdout, _("<standard output>"));
+ }
+
+ return 0;
+}
diff --git a/src/split/join.c b/src/split/join.c
new file mode 100644
index 0000000..51de444
--- /dev/null
+++ b/src/split/join.c
@@ -0,0 +1,151 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * join.c - joining
+ *
+ * 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 <limits.h>
+#include <string.h>
+#include <fcntl.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/buffer.h>
+#include <dpkg/options.h>
+
+#include "dpkg-split.h"
+
+void reassemble(struct partinfo **partlist, const char *outputfile) {
+ struct dpkg_error err;
+ int fd_out, fd_in;
+ int i;
+
+ printf(P_("Putting package %s together from %d part: ",
+ "Putting package %s together from %d parts: ",
+ partlist[0]->maxpartn),
+ partlist[0]->package,partlist[0]->maxpartn);
+
+ fd_out = creat(outputfile, 0644);
+ if (fd_out < 0)
+ ohshite(_("unable to open output file '%.250s'"), outputfile);
+ for (i=0; i<partlist[0]->maxpartn; i++) {
+ struct partinfo *pi = partlist[i];
+
+ fd_in = open(pi->filename, O_RDONLY);
+ if (fd_in < 0)
+ ohshite(_("unable to (re)open input part file '%.250s'"), pi->filename);
+ if (fd_skip(fd_in, pi->headerlen, &err) < 0)
+ ohshit(_("cannot skip split package header for '%s': %s"), pi->filename,
+ err.str);
+ if (fd_fd_copy(fd_in, fd_out, pi->thispartlen, &err) < 0)
+ ohshit(_("cannot append split package part '%s' to '%s': %s"),
+ pi->filename, outputfile, err.str);
+ close(fd_in);
+
+ printf("%d ", i + 1);
+ }
+ if (fsync(fd_out))
+ ohshite(_("unable to sync file '%s'"), outputfile);
+ if (close(fd_out))
+ ohshite(_("unable to close file '%s'"), outputfile);
+
+ printf(_("done\n"));
+}
+
+
+void addtopartlist(struct partinfo **partlist,
+ struct partinfo *pi, struct partinfo *refi) {
+ int i;
+
+ if (strcmp(pi->package,refi->package) ||
+ strcmp(pi->version,refi->version) ||
+ strcmp(pi->md5sum,refi->md5sum) ||
+ pi->orglength != refi->orglength ||
+ pi->maxpartn != refi->maxpartn ||
+ pi->maxpartlen != refi->maxpartlen) {
+ print_info(pi);
+ print_info(refi);
+ ohshit(_("files '%.250s' and '%.250s' are not parts of the same file"),
+ pi->filename,refi->filename);
+ }
+ i= pi->thispartn-1;
+ if (partlist[i])
+ ohshit(_("there are several versions of part %d - at least '%.250s' and '%.250s'"),
+ pi->thispartn, pi->filename, partlist[i]->filename);
+ partlist[i]= pi;
+}
+
+int
+do_join(const char *const *argv)
+{
+ const char *thisarg;
+ struct partqueue *queue = NULL;
+ struct partqueue *pq;
+ struct partinfo *refi, **partlist;
+ int i;
+
+ if (!*argv)
+ badusage(_("--%s requires one or more part file arguments"),
+ cipaction->olong);
+ while ((thisarg= *argv++)) {
+ pq = nfmalloc(sizeof(*pq));
+
+ mustgetpartinfo(thisarg,&pq->info);
+
+ pq->nextinqueue= queue;
+ queue= pq;
+ }
+ refi= NULL;
+ for (pq= queue; pq; pq= pq->nextinqueue)
+ if (!refi || pq->info.thispartn < refi->thispartn) refi= &pq->info;
+ if (refi == NULL)
+ internerr("empty deb part queue");
+
+ partlist = nfmalloc(sizeof(*partlist) * refi->maxpartn);
+ for (i = 0; i < refi->maxpartn; i++)
+ partlist[i] = NULL;
+ for (pq= queue; pq; pq= pq->nextinqueue) {
+ struct partinfo *pi = &pq->info;
+
+ addtopartlist(partlist,pi,refi);
+ }
+ for (i=0; i<refi->maxpartn; i++) {
+ if (!partlist[i]) ohshit(_("part %d is missing"),i+1);
+ }
+ if (!opt_outputfile) {
+ char *p;
+
+ p= nfmalloc(strlen(refi->package)+1+strlen(refi->version)+sizeof(DEBEXT));
+ strcpy(p,refi->package);
+ strcat(p, "_");
+ strcat(p,refi->version);
+ strcat(p, "_");
+ strcat(p, refi->arch ? refi->arch : "unknown");
+ strcat(p,DEBEXT);
+ opt_outputfile = p;
+ }
+ reassemble(partlist, opt_outputfile);
+
+ return 0;
+}
diff --git a/src/split/main.c b/src/split/main.c
new file mode 100644
index 0000000..eba2333
--- /dev/null
+++ b/src/split/main.c
@@ -0,0 +1,185 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * main.c - main program
+ *
+ * Copyright © 1994-1996 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 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 <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/debug.h>
+#include <dpkg/fsys.h>
+#include <dpkg/options.h>
+
+#include "dpkg-split.h"
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian '%s' package split/join tool; version %s.\n"),
+ SPLITTER, PACKAGE_RELEASE);
+
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option> ...] <command>\n"
+"\n"), SPLITTER);
+
+ printf(_(
+"Commands:\n"
+" -s|--split <file> [<prefix>] Split an archive.\n"
+" -j|--join <part> <part> ... Join parts together.\n"
+" -I|--info <part> ... Display info about a part.\n"
+" -a|--auto -o <complete> <part> Auto-accumulate parts.\n"
+" -l|--listq List unmatched pieces.\n"
+" -d|--discard [<filename> ...] Discard unmatched pieces.\n"
+"\n"));
+
+ printf(_(
+" -?, --help Show this help message.\n"
+" --version Show the version.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --depotdir <directory> Use <directory> instead of %s/%s.\n"
+" --admindir <directory> Use <directory> instead of %s.\n"
+" --root <directory> Use <directory> instead of %s.\n"
+" -S, --partsize <size> In KiB, for -s (default is 450).\n"
+" -o, --output <file> Filename, for -j (default is\n"
+" <package>_<version>_<arch>.deb).\n"
+" -Q, --npquiet Be quiet when -a is not a part.\n"
+" --msdos Generate 8.3 filenames.\n"
+"\n"), ADMINDIR, PARTSDIR, ADMINDIR, "/");
+
+ printf(_(
+"Exit status:\n"
+" 0 = ok\n"
+" 1 = with --auto, file is not a part\n"
+" 2 = trouble\n"));
+
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static const char printforhelp[] = N_("Type dpkg-split --help for help.");
+
+off_t opt_maxpartsize = SPLITPARTDEFMAX;
+const char *opt_depotdir;
+const char *opt_outputfile = NULL;
+int opt_npquiet = 0;
+int opt_msdos = 0;
+
+void DPKG_ATTR_NORET
+read_fail(int rc, const char *filename, const char *what)
+{
+ if (rc >= 0)
+ ohshit(_("unexpected end of file in %s in %.255s"), what, filename);
+ else
+ ohshite(_("error reading %s from file %.255s"), what, filename);
+}
+
+static void
+set_part_size(const struct cmdinfo *cip, const char *value)
+{
+ off_t newpartsize;
+ char *endp;
+
+ errno = 0;
+ newpartsize = strtoimax(value, &endp, 10);
+ if (value == endp || *endp)
+ badusage(_("invalid integer for --%s: '%.250s'"), cip->olong, value);
+ if (newpartsize <= 0 || newpartsize > (INT_MAX >> 10) || errno == ERANGE)
+ badusage(_("part size is far too large or is not positive"));
+
+ opt_maxpartsize = newpartsize << 10;
+ if (opt_maxpartsize <= HEADERALLOWANCE)
+ badusage(_("part size must be at least %d KiB (to allow for header)"),
+ (HEADERALLOWANCE >> 10) + 1);
+}
+
+static const struct cmdinfo cmdinfos[]= {
+ ACTION("split", 's', 0, do_split),
+ ACTION("join", 'j', 0, do_join),
+ ACTION("info", 'I', 0, do_info),
+ ACTION("auto", 'a', 0, do_auto),
+ ACTION("listq", 'l', 0, do_queue),
+ ACTION("discard", 'd', 0, do_discard),
+ ACTION("help", '?', 0, usage),
+ ACTION("version", 0, 0, printversion),
+
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "depotdir", 0, 1, NULL, &opt_depotdir, NULL },
+ { "partsize", 'S', 1, NULL, NULL, set_part_size },
+ { "output", 'o', 1, NULL, &opt_outputfile, NULL },
+ { "npquiet", 'Q', 0, &opt_npquiet, NULL, NULL, 1 },
+ { "msdos", 0, 0, &opt_msdos, NULL, NULL, 1 },
+ { NULL, 0 }
+};
+
+int main(int argc, const char *const *argv) {
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init(SPLITTER);
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ if (opt_depotdir == NULL)
+ opt_depotdir = dpkg_db_get_path(PARTSDIR);
+
+ if (!cipaction) badusage(_("need an action option"));
+
+ ret = cipaction->action(argv);
+
+ m_output(stderr, _("<standard error>"));
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return ret;
+}
diff --git a/src/split/queue.c b/src/split/queue.c
new file mode 100644
index 0000000..c9b8847
--- /dev/null
+++ b/src/split/queue.c
@@ -0,0 +1,365 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * queue.c - queue management
+ *
+ * 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 <sys/stat.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/dir.h>
+#include <dpkg/buffer.h>
+#include <dpkg/options.h>
+
+#include "dpkg-split.h"
+
+/*
+ * The queue, by default located in /var/lib/dpkg/parts/, is a plain
+ * directory with one file per part.
+ *
+ * Each part is named “<md5sum>.<maxpartlen>.<thispartn>.<maxpartn>”,
+ * with all numbers in hex.
+ */
+
+
+static bool
+decompose_filename(const char *filename, struct partqueue *pq)
+{
+ const char *p;
+ char *q;
+
+ if (strspn(filename, "0123456789abcdef") != MD5HASHLEN ||
+ filename[MD5HASHLEN] != '.')
+ return false;
+
+ pq->info.md5sum = nfstrnsave(filename, MD5HASHLEN);
+
+ p = filename + MD5HASHLEN + 1;
+ errno = 0;
+ pq->info.maxpartlen = strtoimax(p, &q, 16);
+ if (q == p || *q++ != '.' || errno != 0)
+ return false;
+
+ p = q;
+ pq->info.thispartn = (int)strtol(p, &q, 16);
+ if (q == p || *q++ != '.' || pq->info.thispartn < 0 || errno != 0)
+ return false;
+
+ p = q;
+ pq->info.maxpartn = (int)strtol(p, &q, 16);
+ if (q == p || *q || pq->info.maxpartn < 0 || errno != 0)
+ return false;
+
+ return true;
+}
+
+static struct partqueue *
+scandepot(void)
+{
+ DIR *depot;
+ struct dirent *de;
+ struct partqueue *queue = NULL;
+
+ depot = opendir(opt_depotdir);
+ if (!depot) {
+ if (errno == ENOENT)
+ return NULL;
+
+ ohshite(_("unable to read depot directory '%.250s'"), opt_depotdir);
+ }
+ while ((de= readdir(depot))) {
+ struct partqueue *pq;
+ char *p;
+
+ if (de->d_name[0] == '.') continue;
+ pq = nfmalloc(sizeof(*pq));
+ pq->info.fmtversion.major = 0;
+ pq->info.fmtversion.minor = 0;
+ pq->info.package = NULL;
+ pq->info.version = NULL;
+ pq->info.arch = NULL;
+ pq->info.orglength= pq->info.thispartoffset= pq->info.thispartlen= 0;
+ pq->info.headerlen= 0;
+ p = nfmalloc(strlen(opt_depotdir) + 1 + strlen(de->d_name) + 1);
+ sprintf(p, "%s/%s", opt_depotdir, de->d_name);
+ pq->info.filename= p;
+ if (!decompose_filename(de->d_name,pq)) {
+ pq->info.md5sum= NULL;
+ pq->info.maxpartlen= pq->info.thispartn= pq->info.maxpartn= 0;
+ }
+ pq->nextinqueue= queue;
+ queue= pq;
+ }
+ closedir(depot);
+
+ return queue;
+}
+
+static bool
+partmatches(struct partinfo *pi, struct partinfo *refi)
+{
+ return (pi->md5sum &&
+ strcmp(pi->md5sum, refi->md5sum) == 0 &&
+ pi->maxpartn == refi->maxpartn &&
+ pi->maxpartlen == refi->maxpartlen);
+}
+
+int
+do_auto(const char *const *argv)
+{
+ const char *partfile;
+ struct partinfo *refi, **partlist, *otherthispart;
+ struct partqueue *queue;
+ struct partqueue *pq;
+ struct dpkg_ar *part;
+ int i, j;
+
+ if (!opt_outputfile)
+ badusage(_("--auto requires the use of the --output option"));
+ partfile = *argv++;
+ if (partfile == NULL || *argv)
+ badusage(_("--auto requires exactly one part file argument"));
+
+ refi = nfmalloc(sizeof(*refi));
+ part = dpkg_ar_open(partfile);
+ if (!part)
+ ohshite(_("unable to read part file '%.250s'"), partfile);
+ refi = read_info(part, refi);
+ dpkg_ar_close(part);
+
+ if (refi == NULL) {
+ if (!opt_npquiet)
+ printf(_("File '%.250s' is not part of a multipart archive.\n"), partfile);
+ m_output(stdout, _("<standard output>"));
+ return 1;
+ }
+
+ queue = scandepot();
+ if (queue == NULL)
+ if (dir_make_path(opt_depotdir, 0755) < 0)
+ ohshite(_("cannot create directory %s"), opt_depotdir);
+
+ partlist = nfmalloc(sizeof(*partlist) * refi->maxpartn);
+ for (i = 0; i < refi->maxpartn; i++)
+ partlist[i] = NULL;
+ for (pq= queue; pq; pq= pq->nextinqueue) {
+ struct partinfo *npi, *pi = &pq->info;
+
+ if (!partmatches(pi,refi)) continue;
+ npi = nfmalloc(sizeof(*npi));
+ mustgetpartinfo(pi->filename,npi);
+ addtopartlist(partlist,npi,refi);
+ }
+ /* If we already have a copy of this version we ignore it and prefer the
+ * new one, but we still want to delete the one in the depot, so we
+ * save its partinfo (with the filename) for later. This also prevents
+ * us from accidentally deleting the source file. */
+ otherthispart= partlist[refi->thispartn-1];
+ partlist[refi->thispartn-1]= refi;
+ for (j=refi->maxpartn-1; j>=0 && partlist[j]; j--);
+
+ if (j>=0) {
+ struct dpkg_error err;
+ int fd_src, fd_dst;
+ int ap;
+ char *p, *q;
+
+ p = str_fmt("%s/t.%lx", opt_depotdir, (long)getpid());
+ q = str_fmt("%s/%s.%jx.%x.%x", opt_depotdir, refi->md5sum,
+ (intmax_t)refi->maxpartlen, refi->thispartn, refi->maxpartn);
+
+ fd_src = open(partfile, O_RDONLY);
+ if (fd_src < 0)
+ ohshite(_("unable to reopen part file '%.250s'"), partfile);
+ fd_dst = creat(p, 0644);
+ if (fd_dst < 0)
+ ohshite(_("unable to open new depot file '%.250s'"), p);
+
+ if (fd_fd_copy(fd_src, fd_dst, refi->filesize, &err) < 0)
+ ohshit(_("cannot extract split package part '%s': %s"),
+ partfile, err.str);
+
+ if (fsync(fd_dst))
+ ohshite(_("unable to sync file '%s'"), p);
+ if (close(fd_dst))
+ ohshite(_("unable to close file '%s'"), p);
+ close(fd_src);
+
+ if (rename(p, q))
+ ohshite(_("unable to rename new depot file '%.250s' to '%.250s'"), p, q);
+ free(q);
+ free(p);
+
+ printf(_("Part %d of package %s filed (still want "),refi->thispartn,refi->package);
+ /* There are still some parts missing. */
+ for (i=0, ap=0; i<refi->maxpartn; i++)
+ if (!partlist[i])
+ printf("%s%d", !ap++ ? "" : i == j ? _(" and ") : ", ", i + 1);
+ printf(").\n");
+
+ dir_sync_path(opt_depotdir);
+ } else {
+ /* We have all the parts. */
+ reassemble(partlist, opt_outputfile);
+
+ /* OK, delete all the parts (except the new one, which we never copied). */
+ partlist[refi->thispartn-1]= otherthispart;
+ for (i=0; i<refi->maxpartn; i++)
+ if (partlist[i])
+ if (unlink(partlist[i]->filename))
+ ohshite(_("unable to delete used-up depot file '%.250s'"),
+ partlist[i]->filename);
+ }
+
+ m_output(stderr, _("<standard error>"));
+
+ return 0;
+}
+
+int
+do_queue(const char *const *argv)
+{
+ struct partqueue *queue;
+ struct partqueue *pq;
+ const char *head;
+ struct stat stab;
+ off_t bytes;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), cipaction->olong);
+
+ queue = scandepot();
+
+ head= N_("Junk files left around in the depot directory:\n");
+ for (pq= queue; pq; pq= pq->nextinqueue) {
+ if (pq->info.md5sum) continue;
+ fputs(gettext(head),stdout); head= "";
+ if (lstat(pq->info.filename,&stab))
+ ohshit(_("unable to stat '%.250s'"), pq->info.filename);
+ if (S_ISREG(stab.st_mode)) {
+ bytes= stab.st_size;
+ printf(_(" %s (%jd bytes)\n"), pq->info.filename, (intmax_t)bytes);
+ } else {
+ printf(_(" %s (not a plain file)\n"),pq->info.filename);
+ }
+ }
+ if (!*head) putchar('\n');
+
+ head= N_("Packages not yet reassembled:\n");
+ for (pq= queue; pq; pq= pq->nextinqueue) {
+ struct partinfo ti;
+ int i;
+
+ if (!pq->info.md5sum) continue;
+ mustgetpartinfo(pq->info.filename,&ti);
+ fputs(gettext(head),stdout); head= "";
+ printf(_(" Package %s: part(s) "), ti.package);
+ bytes= 0;
+ for (i=0; i<ti.maxpartn; i++) {
+ struct partqueue *qq;
+
+ for (qq= pq;
+ qq && !(partmatches(&qq->info,&ti) && qq->info.thispartn == i+1);
+ qq= qq->nextinqueue);
+ if (qq) {
+ printf("%d ",i+1);
+ if (lstat(qq->info.filename,&stab))
+ ohshite(_("unable to stat '%.250s'"), qq->info.filename);
+ if (!S_ISREG(stab.st_mode))
+ ohshit(_("part file '%.250s' is not a plain file"), qq->info.filename);
+ bytes+= stab.st_size;
+
+ /* Don't find this package again. */
+ qq->info.md5sum = NULL;
+ }
+ }
+ printf(_("(total %jd bytes)\n"), (intmax_t)bytes);
+ }
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+enum discard_which {
+ DISCARD_PART_JUNK,
+ DISCARD_PART_PACKAGE,
+ DISCARD_PART_ALL,
+};
+
+static void
+discard_parts(struct partqueue *queue, enum discard_which which,
+ const char *package)
+{
+ struct partqueue *pq;
+
+ for (pq= queue; pq; pq= pq->nextinqueue) {
+ switch (which) {
+ case DISCARD_PART_JUNK:
+ if (pq->info.md5sum) continue;
+ break;
+ case DISCARD_PART_PACKAGE:
+ if (!pq->info.md5sum || strcasecmp(pq->info.package,package)) continue;
+ break;
+ case DISCARD_PART_ALL:
+ break;
+ default:
+ internerr("unknown discard_which '%d'", which);
+ }
+ if (unlink(pq->info.filename))
+ ohshite(_("unable to discard '%.250s'"), pq->info.filename);
+ printf(_("Deleted %s.\n"),pq->info.filename);
+ }
+}
+
+int
+do_discard(const char *const *argv)
+{
+ const char *thisarg;
+ struct partqueue *queue;
+ struct partqueue *pq;
+
+ queue = scandepot();
+ if (*argv) {
+ for (pq= queue; pq; pq= pq->nextinqueue)
+ if (pq->info.md5sum)
+ mustgetpartinfo(pq->info.filename,&pq->info);
+ discard_parts(queue, DISCARD_PART_JUNK, NULL);
+ while ((thisarg = *argv++))
+ discard_parts(queue, DISCARD_PART_PACKAGE, thisarg);
+ } else {
+ discard_parts(queue, DISCARD_PART_ALL, NULL);
+ }
+
+ return 0;
+}
diff --git a/src/split/split.c b/src/split/split.c
new file mode 100644
index 0000000..0df8fa7
--- /dev/null
+++ b/src/split/split.c
@@ -0,0 +1,287 @@
+/*
+ * dpkg-split - splitting and joining of multipart *.deb archives
+ * split.c - splitting archives
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2008-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 <inttypes.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdint.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/parsedump.h>
+#include <dpkg/path.h>
+#include <dpkg/string.h>
+#include <dpkg/subproc.h>
+#include <dpkg/buffer.h>
+#include <dpkg/ar.h>
+#include <dpkg/options.h>
+
+#include "dpkg-split.h"
+
+/**
+ * Parse the control file from a .deb package into a struct pkginfo.
+ */
+static struct pkginfo *
+deb_parse_control(const char *filename)
+{
+ struct parsedb_state *ps;
+ struct pkginfo *pkg;
+ pid_t pid;
+ int p[2];
+
+ m_pipe(p);
+
+ pid = subproc_fork();
+ if (pid == 0) {
+ /* Child writes to pipe. */
+ m_dup2(p[1], 1);
+ close(p[0]);
+ close(p[1]);
+
+ execlp(BACKEND, BACKEND, "--info", filename, "control", NULL);
+ ohshite(_("unable to execute %s (%s)"),
+ _("package field value extraction"), BACKEND);
+ }
+ close(p[1]);
+
+ /* Parent reads from pipe. */
+ ps = parsedb_new(_("<dpkg-deb --info pipe>"), p[0], pdb_parse_binary);
+ parsedb_load(ps);
+ parsedb_parse(ps, &pkg);
+ parsedb_close(ps);
+
+ close(p[0]);
+
+ subproc_reap(pid, _("package field value extraction"), SUBPROC_NOPIPE);
+
+ return pkg;
+}
+
+static intmax_t
+parse_timestamp(const char *value)
+{
+ intmax_t timestamp;
+ char *end;
+
+ errno = 0;
+ timestamp = strtoimax(value, &end, 10);
+ if (value == end || *end || errno != 0)
+ ohshite(_("unable to parse timestamp '%.255s'"), value);
+
+ return timestamp;
+}
+
+/* Cleanup filename for use in crippled msdos systems. */
+static char *
+clean_msdos_filename(char *filename)
+{
+ char *d, *s;
+
+ for (s = d = filename; *s; d++, s++) {
+ if (*s == '+')
+ *d = 'x';
+ else if (c_isupper(*s))
+ *d = c_tolower(*s);
+ else if (c_islower(*s) || c_isdigit(*s))
+ *d = *s;
+ else
+ s++;
+ }
+
+ return filename;
+}
+
+static int
+mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
+ bool msdos)
+{
+ struct pkginfo *pkg;
+ struct dpkg_error err;
+ int fd_src;
+ struct stat st;
+ intmax_t timestamp;
+ const char *timestamp_str;
+ const char *version;
+ char hash[MD5HASHLEN + 1];
+ int nparts, curpart;
+ off_t partsize;
+ off_t cur_partsize, last_partsize;
+ char *prefixdir = NULL, *msdos_prefix = NULL;
+ struct varbuf file_dst = VARBUF_INIT;
+ struct varbuf partmagic = VARBUF_INIT;
+ struct varbuf partname = VARBUF_INIT;
+
+ fd_src = open(file_src, O_RDONLY);
+ if (fd_src < 0)
+ ohshite(_("unable to open source file '%.250s'"), file_src);
+ if (fstat(fd_src, &st))
+ ohshite(_("unable to fstat source file"));
+ if (!S_ISREG(st.st_mode))
+ ohshit(_("source file '%.250s' not a plain file"), file_src);
+
+ if (fd_md5(fd_src, hash, -1, &err) < 0)
+ ohshit(_("cannot compute MD5 digest for file '%s': %s"),
+ file_src, err.str);
+ lseek(fd_src, 0, SEEK_SET);
+
+ pkg = deb_parse_control(file_src);
+ version = versiondescribe(&pkg->available.version, vdew_nonambig);
+
+ timestamp_str = getenv("SOURCE_DATE_EPOCH");
+ if (timestamp_str)
+ timestamp = parse_timestamp(timestamp_str);
+ else
+ timestamp = time(NULL);
+
+ partsize = maxpartsize - HEADERALLOWANCE;
+ last_partsize = st.st_size % partsize;
+ if (last_partsize == 0)
+ last_partsize = partsize;
+ nparts = (st.st_size + partsize - 1) / partsize;
+
+ printf(P_("Splitting package %s into %d part: ",
+ "Splitting package %s into %d parts: ", nparts),
+ pkg->set->name, nparts);
+
+ if (msdos) {
+ char *t;
+
+ t = m_strdup(prefix);
+ prefixdir = m_strdup(dirname(t));
+ free(t);
+
+ msdos_prefix = m_strdup(path_basename(prefix));
+ prefix = clean_msdos_filename(msdos_prefix);
+ }
+
+ for (curpart = 1; curpart <= nparts; curpart++) {
+ struct dpkg_ar *ar;
+
+ varbuf_reset(&file_dst);
+ /* Generate output filename. */
+ if (msdos) {
+ char *refname;
+ int prefix_max;
+
+ refname = str_fmt("%dof%d", curpart, nparts);
+ prefix_max = max(8 - strlen(refname), 0);
+ varbuf_printf(&file_dst, "%s/%.*s%.8s.deb",
+ prefixdir, prefix_max, prefix, refname);
+ free(refname);
+ } else {
+ varbuf_printf(&file_dst, "%s.%dof%d.deb",
+ prefix, curpart, nparts);
+ }
+
+ if (curpart == nparts)
+ cur_partsize = last_partsize;
+ else
+ cur_partsize = partsize;
+
+ if (cur_partsize > maxpartsize) {
+ ohshit(_("header is too long, making part too long; "
+ "the package name or version\n"
+ "numbers must be extraordinarily long, "
+ "or something; giving up"));
+ }
+
+ /* Split the data. */
+ ar = dpkg_ar_create(file_dst.buf, 0644);
+ dpkg_ar_set_mtime(ar, timestamp);
+
+ /* Write the ar header. */
+ dpkg_ar_put_magic(ar);
+
+ /* Write the debian-split part. */
+ varbuf_printf(&partmagic,
+ "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
+ SPLITVERSION, pkg->set->name, version, hash,
+ (intmax_t)st.st_size, (intmax_t)partsize,
+ curpart, nparts, pkg->available.arch->name);
+ dpkg_ar_member_put_mem(ar, PARTMAGIC,
+ partmagic.buf, partmagic.used);
+ varbuf_reset(&partmagic);
+
+ /* Write the data part. */
+ varbuf_printf(&partname, "data.%d", curpart);
+ dpkg_ar_member_put_file(ar, partname.buf,
+ fd_src, cur_partsize);
+ varbuf_reset(&partname);
+
+ dpkg_ar_close(ar);
+
+ printf("%d ", curpart);
+ }
+
+ varbuf_destroy(&file_dst);
+ varbuf_destroy(&partname);
+ varbuf_destroy(&partmagic);
+
+ free(prefixdir);
+ free(msdos_prefix);
+
+ close(fd_src);
+
+ printf(_("done\n"));
+
+ return 0;
+}
+
+int
+do_split(const char *const *argv)
+{
+ const char *sourcefile, *prefix;
+
+ sourcefile = *argv++;
+ if (!sourcefile)
+ badusage(_("--split needs a source filename argument"));
+ prefix = *argv++;
+ if (prefix && *argv)
+ badusage(_("--split takes at most a source filename and destination prefix"));
+ if (!prefix) {
+ size_t sourcefile_len = strlen(sourcefile);
+
+ if (str_match_end(sourcefile, DEBEXT))
+ sourcefile_len -= strlen(DEBEXT);
+
+ prefix = nfstrnsave(sourcefile, sourcefile_len);
+ }
+
+ mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
+
+ return 0;
+}
diff --git a/src/statoverride/main.c b/src/statoverride/main.c
new file mode 100644
index 0000000..66fe8c3
--- /dev/null
+++ b/src/statoverride/main.c
@@ -0,0 +1,421 @@
+/*
+ * dpkg-statoverride - override ownership and mode of files
+ *
+ * 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/stat.h>
+
+#include <errno.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <string.h>
+#include <grp.h>
+#include <pwd.h>
+#include <fnmatch.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/debug.h>
+#include <dpkg/string.h>
+#include <dpkg/path.h>
+#include <dpkg/dir.h>
+#include <dpkg/glob.h>
+#include <dpkg/db-fsys.h>
+#include <dpkg/options.h>
+
+#include "force.h"
+#include "actions.h"
+#include "security-mac.h"
+
+static const char printforhelp[] = N_(
+"Use --help for help about overriding file stat information.");
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian %s version %s.\n"), dpkg_get_progname(),
+ PACKAGE_RELEASE);
+
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option> ...] <command>\n"
+"\n"), dpkg_get_progname());
+
+ printf(_(
+"Commands:\n"
+" --add <owner> <group> <mode> <path>\n"
+" add a new <path> entry into the database.\n"
+" --remove <path> remove <path> from the database.\n"
+" --list [<glob-pattern>] list current overrides in the database.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --admindir <directory> set the directory with the statoverride file.\n"
+" --instdir <directory> set the root directory, but not the admin dir.\n"
+" --root <directory> set the directory of the root filesystem.\n"
+" --update immediately update <path> permissions.\n"
+" --force deprecated alias for --force-all.\n"
+" --force-<thing>[,...] override problems (see --force-help).\n"
+" --no-force-<thing>[,...] stop when problems encountered.\n"
+" --refuse-<thing>[,...] ditto.\n"
+" --quiet quiet operation, minimal output.\n"
+" --help show this help message.\n"
+" --version show the version.\n"
+"\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+#define FORCE_STATCMD_MASK \
+ FORCE_NON_ROOT | \
+ FORCE_SECURITY_MAC | FORCE_STATOVERRIDE_ADD | FORCE_STATOVERRIDE_DEL
+
+static int opt_verbose = 1;
+static int opt_update = 0;
+
+static char *
+path_cleanup(const char *path)
+{
+ char *new_path = m_strdup(path);
+
+ path_trim_slash_slashdot(new_path);
+ if (opt_verbose && strcmp(path, new_path) != 0)
+ warning(_("stripping trailing /"));
+
+ return new_path;
+}
+
+static struct file_stat *
+statdb_node_new(const char *user, const char *group, const char *mode)
+{
+ struct file_stat *filestat;
+
+ filestat = nfmalloc(sizeof(*filestat));
+
+ filestat->uid = statdb_parse_uid(user);
+ if (filestat->uid == (uid_t)-1)
+ ohshit(_("user '%s' does not exist"), user);
+ filestat->uname = NULL;
+ filestat->gid = statdb_parse_gid(group);
+ if (filestat->gid == (gid_t)-1)
+ ohshit(_("group '%s' does not exist"), group);
+ filestat->gname = NULL;
+ filestat->mode = statdb_parse_mode(mode);
+
+ return filestat;
+}
+
+static struct file_stat **
+statdb_node_find(const char *filename)
+{
+ struct fsys_namenode *file;
+
+ file = fsys_hash_find_node(filename, 0);
+
+ return &file->statoverride;
+}
+
+static int
+statdb_node_remove(const char *filename)
+{
+ struct fsys_namenode *file;
+
+ file = fsys_hash_find_node(filename, FHFF_NONE);
+ if (!file || !file->statoverride)
+ return 0;
+
+ file->statoverride = NULL;
+
+ return 1;
+}
+
+static void
+statdb_node_apply(const char *filename, struct file_stat *filestat)
+{
+ int rc;
+
+ rc = chown(filename, filestat->uid, filestat->gid);
+ if (forcible_nonroot_error(rc) < 0)
+ ohshite(_("error setting ownership of '%.255s'"), filename);
+ rc = chmod(filename, filestat->mode & ~S_IFMT);
+ if (forcible_nonroot_error(rc) < 0)
+ ohshite(_("error setting permissions of '%.255s'"), filename);
+
+ dpkg_selabel_load();
+ dpkg_selabel_set_context(filename, filename, filestat->mode);
+ dpkg_selabel_close();
+}
+
+static void
+statdb_node_print(FILE *out, struct fsys_namenode *file)
+{
+ struct file_stat *filestat = file->statoverride;
+ struct passwd *pw;
+ struct group *gr;
+
+ if (!filestat)
+ return;
+
+ pw = getpwuid(filestat->uid);
+ if (pw)
+ fprintf(out, "%s ", pw->pw_name);
+ else if (filestat->uname)
+ fprintf(out, "%s ", filestat->uname);
+ else
+ fprintf(out, "#%d ", filestat->uid);
+
+ gr = getgrgid(filestat->gid);
+ if (gr)
+ fprintf(out, "%s ", gr->gr_name);
+ else if (filestat->gname)
+ fprintf(out, "%s ", filestat->gname);
+ else
+ fprintf(out, "#%d ", filestat->gid);
+
+ fprintf(out, "%o %s\n", filestat->mode & ~S_IFMT, file->name);
+}
+
+static void
+statdb_write(void)
+{
+ char *dbname;
+ struct atomic_file *dbfile;
+ struct fsys_hash_iter *iter;
+ struct fsys_namenode *file;
+
+ dbname = dpkg_db_get_path(STATOVERRIDEFILE);
+ dbfile = atomic_file_new(dbname, ATOMIC_FILE_BACKUP);
+ atomic_file_open(dbfile);
+
+ iter = fsys_hash_iter_new();
+ while ((file = fsys_hash_iter_next(iter)))
+ statdb_node_print(dbfile->fp, file);
+ fsys_hash_iter_free(iter);
+
+ atomic_file_sync(dbfile);
+ atomic_file_close(dbfile);
+ atomic_file_commit(dbfile);
+ atomic_file_free(dbfile);
+
+ dir_sync_path(dpkg_db_get_dir());
+
+ free(dbname);
+}
+
+static int
+statoverride_add(const char *const *argv)
+{
+ const char *user = argv[0];
+ const char *group = argv[1];
+ const char *mode = argv[2];
+ const char *path = argv[3];
+ char *filename;
+ struct file_stat **filestat;
+
+ if (!user || !group || !mode || !path || argv[4])
+ badusage(_("--%s needs four arguments"), cipaction->olong);
+
+ if (strchr(path, '\n'))
+ badusage(_("path may not contain newlines"));
+
+ ensure_statoverrides(STATDB_PARSE_LAX);
+
+ filename = path_cleanup(path);
+
+ filestat = statdb_node_find(filename);
+ if (*filestat != NULL) {
+ if (in_force(FORCE_STATOVERRIDE_ADD))
+ warning(_("an override for '%s' already exists, "
+ "but --force specified so will be ignored"),
+ filename);
+ else
+ ohshit(_("an override for '%s' already exists; "
+ "aborting"), filename);
+ }
+
+ *filestat = statdb_node_new(user, group, mode);
+
+ if (opt_update) {
+ struct stat st;
+ struct varbuf realfilename = VARBUF_INIT;
+
+ varbuf_add_str(&realfilename, dpkg_fsys_get_dir());
+ varbuf_add_str(&realfilename, filename);
+ varbuf_end_str(&realfilename);
+
+ if (stat(realfilename.buf, &st) == 0) {
+ (*filestat)->mode |= st.st_mode & S_IFMT;
+ statdb_node_apply(realfilename.buf, *filestat);
+ } else if (opt_verbose) {
+ warning(_("--update given but %s does not exist"),
+ realfilename.buf);
+ }
+
+ varbuf_destroy(&realfilename);
+ }
+
+ statdb_write();
+
+ free(filename);
+
+ return 0;
+}
+
+static int
+statoverride_remove(const char *const *argv)
+{
+ const char *path = argv[0];
+ char *filename;
+
+ if (!path || argv[1])
+ badusage(_("--%s needs a single argument"), "remove");
+
+ ensure_statoverrides(STATDB_PARSE_LAX);
+
+ filename = path_cleanup(path);
+
+ if (!statdb_node_remove(filename)) {
+ if (opt_verbose)
+ warning(_("no override present"));
+ if (in_force(FORCE_STATOVERRIDE_DEL))
+ return 0;
+ else
+ return 2;
+ }
+
+ if (opt_update && opt_verbose)
+ warning(_("--update is useless for --remove"));
+
+ statdb_write();
+
+ free(filename);
+
+ return 0;
+}
+
+static int
+statoverride_list(const char *const *argv)
+{
+ struct fsys_hash_iter *iter;
+ struct fsys_namenode *file;
+ const char *thisarg;
+ struct glob_node *glob_list = NULL;
+ int ret = 1;
+
+ ensure_statoverrides(STATDB_PARSE_LAX);
+
+ while ((thisarg = *argv++)) {
+ char *pattern = path_cleanup(thisarg);
+
+ glob_list_prepend(&glob_list, pattern);
+ }
+ if (glob_list == NULL)
+ glob_list_prepend(&glob_list, m_strdup("*"));
+
+ iter = fsys_hash_iter_new();
+ while ((file = fsys_hash_iter_next(iter))) {
+ struct glob_node *g;
+
+ for (g = glob_list; g; g = g->next) {
+ if (fnmatch(g->pattern, file->name, 0) == 0) {
+ statdb_node_print(stdout, file);
+ ret = 0;
+ break;
+ }
+ }
+ }
+ fsys_hash_iter_free(iter);
+
+ glob_list_free(glob_list);
+
+ return ret;
+}
+
+static void
+set_force_obsolete(const struct cmdinfo *cip, const char *value)
+{
+ warning(_("deprecated --%s option; use --%s instead"),
+ cip->olong, "force-all");
+ set_force(FORCE_ALL);
+}
+
+static const struct cmdinfo cmdinfos[] = {
+ ACTION("add", 0, act_install, statoverride_add),
+ ACTION("remove", 0, act_remove, statoverride_remove),
+ ACTION("list", 0, act_listfiles, statoverride_list),
+ ACTION("help", '?', act_help, usage),
+ ACTION("version", 0, act_version, printversion),
+
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "instdir", 0, 1, NULL, NULL, set_instdir, 0 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "quiet", 0, 0, &opt_verbose, NULL, NULL, 0 },
+ { "force", 0, 0, NULL, NULL, set_force_obsolete },
+ { "force", 0, 2, NULL, NULL, set_force_option, 1 },
+ { "no-force", 0, 2, NULL, NULL, set_force_option, 0 },
+ { "refuse", 0, 2, NULL, NULL, set_force_option, 0 },
+ { "update", 0, 0, &opt_update, NULL, NULL, 1 },
+ { NULL, 0 }
+};
+
+int
+main(int argc, const char *const *argv)
+{
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init("dpkg-statoverride");
+ set_force_default(FORCE_STATCMD_MASK);
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ if (!cipaction)
+ badusage(_("need an action option"));
+
+ ret = cipaction->action(argv);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return ret;
+}
diff --git a/src/trigger/main.c b/src/trigger/main.c
new file mode 100644
index 0000000..0cc25a4
--- /dev/null
+++ b/src/trigger/main.c
@@ -0,0 +1,270 @@
+/*
+ * dpkg-trigger - trigger management utility
+ *
+ * Copyright © 2007 Canonical Ltd.
+ * Written by 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 <sys/types.h>
+
+#include <fcntl.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <string.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/debug.h>
+#include <dpkg/options.h>
+#include <dpkg/trigdeferred.h>
+#include <dpkg/triglib.h>
+#include <dpkg/pkg-spec.h>
+
+static const char printforhelp[] = N_(
+"Type dpkg-trigger --help for help about this utility.");
+
+static int
+printversion(const char *const *argv)
+{
+ printf(_("Debian %s package trigger utility version %s.\n"),
+ dpkg_get_progname(), PACKAGE_RELEASE);
+
+ printf(_(
+"This is free software; see the GNU General Public License version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int
+usage(const char *const *argv)
+{
+ printf(_(
+"Usage: %s [<option>...] <trigger-name>\n"
+" %s [<option>...] <command>\n"
+"\n"), dpkg_get_progname(), dpkg_get_progname());
+
+ printf(_(
+"Commands:\n"
+" --check-supported Check if the running dpkg supports triggers.\n"
+"\n"));
+
+ printf(_(
+" -?, --help Show this help message.\n"
+" --version Show the version.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --admindir=<directory> Use <directory> instead of %s.\n"
+" --root=<directory> Use <directory> instead of %s.\n"
+" --by-package=<package> Override trigger awaiter (normally set\n"
+" by dpkg).\n"
+" --await Package needs to await the processing.\n"
+" --no-await No package needs to await the processing.\n"
+" --no-act Just test - don't actually change anything.\n"
+"\n"), ADMINDIR, "/");
+
+ m_output(stdout, _("<standard output>"));
+
+ return 0;
+}
+
+static int f_noact;
+static int f_await = 1;
+
+static const char *bypackage, *activate;
+static bool done_trig, ctrig;
+
+static void
+yespackage(const char *awname)
+{
+ trigdef_update_printf(" %s", awname);
+}
+
+static const char *
+parse_awaiter_package(void)
+{
+ struct dpkg_error err = DPKG_ERROR_INIT;
+ struct pkginfo *pkg;
+
+ if (!f_await)
+ bypackage = "-";
+
+ if (bypackage == NULL) {
+ const char *pkgname, *archname;
+
+ pkgname = getenv("DPKG_MAINTSCRIPT_PACKAGE");
+ archname = getenv("DPKG_MAINTSCRIPT_ARCH");
+ if (pkgname == NULL || archname == NULL)
+ badusage(_("must be called from a maintainer script"
+ " (or with a --by-package option)"));
+
+ pkg = pkg_spec_find_pkg(pkgname, archname, &err);
+ } else if (strcmp(bypackage, "-") == 0) {
+ pkg = NULL;
+ } else {
+ pkg = pkg_spec_parse_pkg(bypackage, &err);
+ }
+
+ /* Normalize the bypackage name if there was no error. */
+ if (pkg)
+ bypackage = pkg_name(pkg, pnaw_same);
+
+ return err.str;
+}
+
+static void
+tdm_add_trig_begin(const char *trig)
+{
+ ctrig = strcmp(trig, activate) == 0;
+ trigdef_update_printf("%s", trig);
+ if (!ctrig || done_trig)
+ return;
+ yespackage(bypackage);
+ done_trig = true;
+}
+
+static void
+tdm_add_package(const char *awname)
+{
+ if (ctrig && strcmp(awname, bypackage) == 0)
+ return;
+ yespackage(awname);
+}
+
+static void
+tdm_add_trig_end(void)
+{
+ trigdef_update_printf("\n");
+}
+
+static const struct trigdefmeths tdm_add = {
+ .trig_begin = tdm_add_trig_begin,
+ .package = tdm_add_package,
+ .trig_end = tdm_add_trig_end,
+};
+
+static int
+do_trigger(const char *const *argv)
+{
+ const char *badname;
+ enum trigdef_update_flags tduf;
+ enum trigdef_update_status tdus;
+
+ if (!*argv || argv[1])
+ badusage(_("takes one argument, the trigger name"));
+
+ badname = parse_awaiter_package();
+ if (badname)
+ badusage(_("illegal awaited package name '%.250s': %.250s"),
+ bypackage, badname);
+
+ activate = argv[0];
+ badname = trig_name_is_illegal(activate);
+ if (badname)
+ badusage(_("invalid trigger name '%.250s': %.250s"),
+ activate, badname);
+
+ trigdef_set_methods(&tdm_add);
+
+ tduf = TDUF_NO_LOCK_OK;
+ if (!f_noact)
+ tduf |= TDUF_WRITE | TDUF_WRITE_IF_EMPTY;
+ tdus = trigdef_update_start(tduf);
+ if (tdus >= 0) {
+ trigdef_parse();
+ if (!done_trig)
+ trigdef_update_printf("%s %s\n", activate, bypackage);
+ trigdef_process_done();
+ }
+
+ return 0;
+}
+
+static int
+do_check(const char *const *argv)
+{
+ enum trigdef_update_status uf;
+
+ if (*argv)
+ badusage(_("--%s takes no arguments"), "check-supported");
+
+ uf = trigdef_update_start(TDUF_NO_LOCK_OK);
+ switch (uf) {
+ case TDUS_ERROR_NO_DIR:
+ notice(_("triggers data directory not yet created"));
+ return 1;
+ case TDUS_ERROR_NO_DEFERRED:
+ notice(_("trigger records not yet in existence"));
+ return 1;
+ case TDUS_OK:
+ case TDUS_ERROR_EMPTY_DEFERRED:
+ return 0;
+ default:
+ internerr("unknown trigdef_update_start return value '%d'", uf);
+ }
+}
+
+static const struct cmdinfo cmdinfo_trigger =
+ ACTION("trigger", 0, 0, do_trigger);
+
+static const struct cmdinfo cmdinfos[] = {
+ ACTION("check-supported", 0, 0, do_check),
+ ACTION("help", '?', 0, usage),
+ ACTION("version", 0, 0, printversion),
+
+ { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
+ { "root", 0, 1, NULL, NULL, set_root, 0 },
+ { "by-package", 'f', 1, NULL, &bypackage },
+ { "await", 0, 0, &f_await, NULL, NULL, 1 },
+ { "no-await", 0, 0, &f_await, NULL, NULL, 0 },
+ { "no-act", 0, 0, &f_noact, NULL, NULL, 1 },
+ { NULL }
+};
+
+int
+main(int argc, const char *const *argv)
+{
+ int ret;
+
+ dpkg_locales_init(PACKAGE);
+ dpkg_program_init("dpkg-trigger");
+ dpkg_options_parse(&argv, cmdinfos, printforhelp);
+
+ debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
+
+ if (!cipaction)
+ setaction(&cmdinfo_trigger, NULL);
+
+ ret = cipaction->action(argv);
+
+ dpkg_program_done();
+ dpkg_locales_done();
+
+ return ret;
+}