diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 18:35:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 18:35:28 +0000 |
commit | ea314d2f45c40a006c0104157013ab4b857f665f (patch) | |
tree | 3ef2971cb3675c318b8d9effd987854ad3f6d3e8 /src | |
parent | Initial commit. (diff) | |
download | dpkg-ea314d2f45c40a006c0104157013ab4b857f665f.tar.xz dpkg-ea314d2f45c40a006c0104157013ab4b857f665f.zip |
Adding upstream version 1.22.4.upstream/1.22.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
62 files changed, 35978 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..31d1a9e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,180 @@ +## 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 \ + dpkg-db-keeper \ + # EOL + +EXTRA_DIST += \ + dpkg-db-backup.sh \ + dpkg-db-keeper.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..88b2456 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,1411 @@ +# 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-headers.m4 $(top_srcdir)/m4/dpkg-libs.m4 \ + $(top_srcdir)/m4/dpkg-linker.m4 $(top_srcdir)/m4/dpkg-progs.m4 \ + $(top_srcdir)/m4/dpkg-types.m4 \ + $(top_srcdir)/m4/dpkg-unicode.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/host-cpu-c-abi.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(nobase_dist_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@ +DEB_DEFAULT_COMPRESSOR = @DEB_DEFAULT_COMPRESSOR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DPKG_DEFAULT_PAGER = @DPKG_DEFAULT_PAGER@ +DPKG_DEFAULT_SHELL = @DPKG_DEFAULT_SHELL@ +DPKG_PAGER = @DPKG_PAGER@ +DPKG_SHELL = @DPKG_SHELL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GCOV = @GCOV@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_DOT = @HAVE_DOT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +KVM_LIBS = @KVM_LIBS@ +LCOV = @LCOV@ +LCOV_GENHTML = @LCOV_GENHTML@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LZMA_LIBS = @LZMA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MD_LIBS = @MD_LIBS@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_BUG_WEB = @PACKAGE_BUG_WEB@ +PACKAGE_COPYRIGHT_HOLDER = @PACKAGE_COPYRIGHT_HOLDER@ +PACKAGE_CPAN_NAME = @PACKAGE_CPAN_NAME@ +PACKAGE_DIST_IS_RELEASE = @PACKAGE_DIST_IS_RELEASE@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_RELEASE_DATE = @PACKAGE_RELEASE_DATE@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VCS_TYPE = @PACKAGE_VCS_TYPE@ +PACKAGE_VCS_URL = @PACKAGE_VCS_URL@ +PACKAGE_VCS_WEB = @PACKAGE_VCS_WEB@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATCH = @PATCH@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_COVER = @PERL_COVER@ +PERL_COVERAGE = @PERL_COVERAGE@ +PERL_LIBDIR = @PERL_LIBDIR@ +PERL_MIN_VERSION = @PERL_MIN_VERSION@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PO4A = @PO4A@ +POD2MAN = @POD2MAN@ +POSUB = @POSUB@ +PS_LIBS = @PS_LIBS@ +RANLIB = @RANLIB@ +RT_LIBS = @RT_LIBS@ +SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKET_LIBS = @SOCKET_LIBS@ +STRIP = @STRIP@ +TAR = @TAR@ +USE_NLS = @USE_NLS@ +USE_PO4A = @USE_PO4A@ +USE_UNICODE = @USE_UNICODE@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +ZSTD_LIBS = @ZSTD_LIBS@ +Z_LIBS = @Z_LIBS@ +Z_NG_LIBS = @Z_NG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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-db-keeper.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 \ + dpkg-db-keeper \ + # 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)\":" \ + -e "s:^TAR=.*$$:TAR='$(TAR)':" \ + # 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..8b413ef --- /dev/null +++ b/src/at/atlocal.in @@ -0,0 +1,40 @@ +# Global shell definitions for the autotest test suite + +PATH="@abs_top_builddir@/src:$PATH" +export PATH + +GREP="@GREP@" +EGREP="@EGREP@" +TAR="@TAR@" +PERL="@PERL@" + +if ! command -v lzma >/dev/null && command -v xz >/dev/null; then + lzma() { + xz --format=lzma "$@" + } +fi + +# 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..ccc733a --- /dev/null +++ b/src/at/deb-fields.at @@ -0,0 +1,53 @@ +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], + [s/^Package: .*$/$&\nPackage-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], + [s/^Version:.*$/$&\nRevision: 1/]) +DPKG_MOD_CONTROL([pkg-obsolete-fields], + [s/^Package:.*$/$&\nOptional: suggests/]) +DPKG_MOD_CONTROL([pkg-obsolete-fields], + [s/^Package:.*$/$&\nRecommended: 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..e67ee10 --- /dev/null +++ b/src/at/deb-format.at @@ -0,0 +1,666 @@ +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 -b pkg-old-templ >/dev/null + +dpkg-deb --ctrl-tarfile pkg-old-templ.deb >ctrl.tar +dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar +gzip -n ctrl.tar +gzip -n fsys.tar + +# Create deb-old 0.939 +echo '0.939000' >pkg-old.deb +DPKG_FILE_SIZE([ctrl.tar.gz]) >>pkg-old.deb +cat ctrl.tar.gz >>pkg-old.deb +cat fsys.tar.gz >>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 +]) + +DEB_OLD_CTRL_SIZE=$(DPKG_FILE_SIZE([ctrl.tar.gz])) +DEB_OLD_FSYS_SIZE=$(DPKG_FILE_SIZE([fsys.tar.gz])) +DEB_OLD_SIZE=$(DPKG_FILE_SIZE([pkg-old.deb])) + +AT_CHECK_UNQUOTED([ +# Check old package metadata +dpkg-deb -I pkg-old.deb +], [], [ old Debian package, version 0.939000. + size $DEB_OLD_SIZE bytes: control archive=$DEB_OLD_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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 +]) + +DEB_OLD_0931_SIZE=$(DPKG_FILE_SIZE([pkg-old-0931.deb])) +DEB_OLD_0931_CTRL_SIZE=$(DPKG_FILE_SIZE([ctrl-0931.tar.gz])) + +AT_CHECK_UNQUOTED([ +# Check old package metadata +dpkg-deb -I pkg-old-0931.deb +], [], [ old Debian package, version 0.931000. + size $DEB_OLD_0931_SIZE bytes: control archive=$DEB_OLD_0931_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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 +]) + +DEB_OLD_0932_SIZE=$(DPKG_FILE_SIZE([pkg-old-0932.deb])) +DEB_OLD_0932_CTRL_SIZE=$(DPKG_FILE_SIZE([ctrl-0932.tar.gz])) + +AT_CHECK_UNQUOTED([ +# Check old package metadata +dpkg-deb -I pkg-old-0932.deb +], [], [ old Debian package, version 0.932000. + size $DEB_OLD_0932_SIZE bytes: control archive=$DEB_OLD_0932_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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 +]) + +DEB_OLD_0933_SIZE=$(DPKG_FILE_SIZE([pkg-old-0933.deb])) +DEB_OLD_0933_CTRL_SIZE=$DEB_OLD_0932_CTRL_SIZE + +AT_CHECK_UNQUOTED([ +# Check old package metadata +dpkg-deb -I pkg-old-0933.deb +], [], [ old Debian package, version 0.933000. + size $DEB_OLD_0933_SIZE bytes: control archive=$DEB_OLD_0933_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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 + +m4_define([DPKG_GEN_PKG_DEB_FORMAT_TEMPL], [ + 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + ]) +]) + + +AT_SETUP([dpkg-deb .deb format 2.x (core)]) +AT_KEYWORDS([dpkg-deb deb]) + +AT_SKIP_IF([! command -v gzip >/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 +]) + +AT_DATA([unknown], []) + +DPKG_GEN_PKG_DEB_FORMAT_TEMPL() + +AT_CHECK([ +# Test debian-binary with 2.x versions +echo 2.999 >debian-binary +ar qSc pkg-version-2x.deb debian-binary control.tar data.tar +ar t pkg-version-2x.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-version-2x.deb +], [], [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 +echo "extra line" >>debian-binary +ar qSc pkg-magic-extra.deb debian-binary control.tar data.tar +ar t pkg-magic-extra.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-magic-extra.deb +], [], [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 +ar qSc pkg-duplicate-magic.deb debian-binary debian-binary control.tar data.tar +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 +ar qSc pkg-duplicate-control.deb debian-binary control.tar control.tar data.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) +ar qSc pkg-mixed-1-member.deb debian-binary unknown control.tar data.tar +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) +ar qSc pkg-mixed-2-member.deb debian-binary control.tar unknown data.tar +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 qS pkg-extra-member.deb unknown +ar t pkg-extra-member.deb +dpkg-deb -I pkg-extra-member.deb +], [], [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_DATA([_ignore], []) +AT_CHECK([ +# Test _ member +ar qSc pkg-under-member.deb debian-binary _ignore control.tar data.tar +ar t pkg-under-member.deb +dpkg-deb -I pkg-under-member.deb +], [], [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 +$PERL -E 'print "\0" x 4096' >data.tar.bad +ar qSc 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 qSc pkg-control-none.deb debian-binary control.tar data.tar +ar t pkg-control-none.deb +dpkg-deb -I pkg-control-none.deb +], [], [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 data.tar member +ar qSc 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 qSc 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 +]) + +# Create .deb with non-uniform data.tar/control.tar member compression +ar qSc pkg-mixed-comp.deb debian-binary control.tar data.tar.gz +DEB_MIXED_COMP_SIZE=$(DPKG_FILE_SIZE([pkg-mixed-comp.deb])) + +AT_CHECK_UNQUOTED([ +# Test non-uniform data.tar/control.tar member compression +ar t pkg-mixed-comp.deb +dpkg-deb -I pkg-mixed-comp.deb +dpkg-deb -c pkg-mixed-comp.deb +], [], [debian-binary +control.tar +data.tar.gz + new Debian package, version 2.0. + size $DEB_MIXED_COMP_SIZE 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 +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_CLEANUP + + +AT_SETUP([dpkg-deb .deb format 2.x (xz)]) +AT_KEYWORDS([dpkg-deb deb]) + +AT_SKIP_IF([! command -v gzip >/dev/null]) +AT_SKIP_IF([! command -v xz >/dev/null]) + +DPKG_GEN_PKG_DEB_FORMAT_TEMPL() +AT_CHECK([ +# Extract the base members +xz -c control.tar >control.tar.xz +xz -c data.tar >data.tar.xz +]) + +AT_CHECK([ +# Test control.tar.xz member +ar qSc 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 data.tar.xz member +ar qSc 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 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_CLEANUP + + +AT_SETUP([dpkg-deb .deb format 2.x (zstd)]) +AT_KEYWORDS([dpkg-deb deb]) + +AT_SKIP_IF([! command -v gzip >/dev/null]) +AT_SKIP_IF([! command -v zstd >/dev/null]) + +DPKG_GEN_PKG_DEB_FORMAT_TEMPL() +AT_CHECK([ +# Extract the base members +zstd -c control.tar >control.tar.zst +zstd -c data.tar >data.tar.zst +]) + +AT_CHECK([ +# Test control.tar.zst member +ar qSc 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.zst member +ar qSc 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 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 + + +AT_SETUP([dpkg-deb .deb format 2.x (bzip2)]) +AT_KEYWORDS([dpkg-deb deb]) + +AT_SKIP_IF([! command -v gzip >/dev/null]) +AT_SKIP_IF([! command -v bzip2 >/dev/null]) + +DPKG_GEN_PKG_DEB_FORMAT_TEMPL() +AT_CHECK([ +# Extract the base members +bzip2 -c data.tar >data.tar.bz2 +]) + +AT_CHECK([ +# Test data.tar.bz2 member +ar qSc 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_CLEANUP + + +AT_SETUP([dpkg-deb .deb format 2.x (lzma)]) +AT_KEYWORDS([dpkg-deb deb]) + +AT_SKIP_IF([! command -v gzip >/dev/null]) +AT_SKIP_IF([! command -v lzma >/dev/null]) + +DPKG_GEN_PKG_DEB_FORMAT_TEMPL() +AT_CHECK([ +# Extract the base members +lzma -c data.tar >data.tar.lzma +]) + +AT_CHECK([ +# Test data.tar.lzma member +ar qSc 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_CLEANUP diff --git a/src/at/deb-split.at b/src/at/deb-split.at new file mode 100644 index 0000000..69e777b --- /dev/null +++ b/src/at/deb-split.at @@ -0,0 +1,225 @@ +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 DPKG_SEQ([10]); do + test -f pkg-split-part.${p}of10.deb +done +ar x pkg-split-part.1of10.deb data.1 +], [], [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 +ar x pkg-split-part.1of10.deb debian-split +$PERL -p -i -E 's/.*/2.999/ if $. == 1' debian-split +ar qSc pkg-split-part-version-2x.deb debian-split data.1 +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 +ar x pkg-split-part.1of10.deb debian-split +echo "extra line" >>debian-split +ar qSc pkg-split-part-magic-extra.deb debian-split data.1 +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 +ar x pkg-split-part.1of10.deb debian-split data.1 +ar qSc pkg-split-part-duplicate-magic.deb debian-split debian-split data.1 +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 qS 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..667ccaf --- /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([$EGREP -q '(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([$EGREP -q '(conflicting|two).*remove.*add.*' stderr]) + +AT_CHECK([DPKG_DIVERT --divert], [2], [], [stderr]) +AT_CHECK([$EGREP -q '(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([$EGREP -q '(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([$EGREP -q '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([$EGREP -q 'mismatch on (package|divert-to)' stderr]) + +AT_CHECK([DPKG_DIVERT --rename --divert /testdir/foo.distrib --remove /testdir/foo], + [], [stdout]) +AT_CHECK([$EGREP -q '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([$EGREP -q '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([$EGREP -q '(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([$EGREP -q '(corrupt|unexpected end of file)' stderr]) + +DPKG_GEN_DB_DIVERSIONS([/bin/sh +bash +]) + +AT_CHECK([DPKG_DIVERT --list], [2], [], [stderr]) +AT_CHECK([$EGREP -q '(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([$EGREP -q '(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..a49311c --- /dev/null +++ b/src/at/local.at @@ -0,0 +1,141 @@ +# 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_SEQ($max) +m4_define([DPKG_SEQ], [dnl + m4_for([i], [1], [$1], [], [i ])dnl +]) + +# DPKG_CWD() +m4_define([DPKG_CWD], [dnl + $PERL -MCwd=realpath,getcwd -E 'say realpath(getcwd())'dnl +]) + +# DPKG_FILE_SIZE($filename) +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], [$perlexpr]) +m4_define([DPKG_MOD_CONTROL], [ + $PERL -p -i -E '$2' '$1/DEBIAN/control' +]) diff --git a/src/at/package.m4 b/src/at/package.m4 new file mode 100644 index 0000000..ca9daa9 --- /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.22.4]) +m4_define([AT_PACKAGE_STRING], [dpkg 1.22.4]) +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..40e371d --- /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 -sf aa/bb/cc/file zz/yy/xx/symlink-rel +ln -sf /aa/bb/cc/file zz/yy/xx/symlink-abs +AT_DATA([usr/bin/a-shell], []) +ln -sf /usr/bin/a-shell usr/bin/sh + +tmpdir="$(DPKG_CWD)" +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..aea9493 --- /dev/null +++ b/src/at/testsuite @@ -0,0 +1,13102 @@ +#! /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:208;dpkg-deb .deb format 2.x (core);dpkg-deb deb; +4;deb-format.at:511;dpkg-deb .deb format 2.x (xz);dpkg-deb deb; +5;deb-format.at:562;dpkg-deb .deb format 2.x (zstd);dpkg-deb deb; +6;deb-format.at:613;dpkg-deb .deb format 2.x (bzip2);dpkg-deb deb; +7;deb-format.at:641;dpkg-deb .deb format 2.x (lzma);dpkg-deb deb; +8;deb-content.at:1;dpkg-deb .deb conffiles;dpkg-deb deb conffiles; +9;deb-fields.at:1;dpkg-deb .deb fields;dpkg-deb deb fields; +10;deb-split.at:1;dpkg-split options;dpkg-split command-line; +11;deb-split.at:9;dpkg-split .deb format;dpkg-split deb-split; +12;realpath.at:1;dpkg-realpath options;dpkg-realpath command-line; +13;realpath.at:9;dpkg-realpath path resolving;dpkg-realpath canonicalize; +14;divert.at:1;dpkg-divert options;dpkg-divert command-line; +15;divert.at:83;dpkg-divert query (empty db);dpkg-divert query; +16;divert.at:94;dpkg-divert query (list);dpkg-divert query; +17;divert.at:134;dpkg-divert query (listpackage + truename);dpkg-divert query; +18;divert.at:160;dpkg-divert add (local rename);dpkg-divert add; +19;divert.at:178;dpkg-divert add (local no-rename);dpkg-divert add; +20;divert.at:196;dpkg-divert add (rename quiet);dpkg-divert add; +21;divert.at:213;dpkg-divert add (test rename quiet);dpkg-divert add; +22;divert.at:226;dpkg-divert add (rename missing quiet);dpkg-divert add; +23;divert.at:243;dpkg-divert add (local rename quiet);dpkg-divert add; +24;divert.at:260;dpkg-divert add (package rename quiet);dpkg-divert add; +25;divert.at:274;dpkg-divert add (rename self-link);dpkg-divert add; +26;divert.at:292;dpkg-divert add (rename other-file);dpkg-divert add; +27;divert.at:305;dpkg-divert add (rename missing dir);dpkg-divert add; +28;divert.at:319;dpkg-divert add (rename read-only dir);dpkg-divert fsys; +29;divert.at:343;dpkg-divert add (rename no-access dir);dpkg-divert fsys; +30;divert.at:367;dpkg-divert add second diversion;dpkg-divert add; +31;divert.at:401;dpkg-divert add third diversion;dpkg-divert add; +32;divert.at:420;dpkg-divert add (file owned by --package);dpkg-divert add; +33;divert.at:447;dpkg-divert remove (missing);dpkg-divert remove; +34;divert.at:459;dpkg-divert remove (divert-to);dpkg-divert remove; +35;divert.at:494;dpkg-divert remove (plain);dpkg-divert remove; +36;divert.at:517;dpkg-divert remove (by-package);dpkg-divert remove; +37;divert.at:539;dpkg-divert remove (test);dpkg-divert remove; +38;divert.at:564;dpkg-divert db (no-access);dpkg-divert db; +39;divert.at:580;dpkg-divert db (truncated);dpkg-divert db; +40;divert.at:598;dpkg-divert db (read-only dir);dpkg-divert db; +41;divert.at:613;dpkg-divert db (disk full);dpkg-divert db; +42;divert.at:628;dpkg-divert db (pathname is dir);dpkg-divert db; +43;chdir.at:5;dpkg chdir opts;dpkg command-line chdir; +44;chdir.at:5;dpkg chdir env;dpkg command-line chdir; +45;chdir.at:5;dpkg chdir env+opt admindir;dpkg command-line chdir; +46;chdir.at:5;dpkg chdir env+opt root;dpkg command-line chdir; +47;chdir.at:5;dpkg chdir env+opt root+admindir;dpkg command-line chdir; +48;chdir.at:5;dpkg-divert chdir opts;dpkg-divert command-line chdir; +49;chdir.at:5;dpkg-divert chdir env;dpkg-divert command-line chdir; +50;chdir.at:5;dpkg-divert chdir env+opt admindir;dpkg-divert command-line chdir; +51;chdir.at:5;dpkg-divert chdir env+opt root;dpkg-divert command-line chdir; +52;chdir.at:5;dpkg-divert chdir env+opt root+admindir;dpkg-divert command-line chdir; +53;chdir.at:5;dpkg-statoverride chdir opts;dpkg-statoverride command-line chdir; +54;chdir.at:5;dpkg-statoverride chdir env;dpkg-statoverride command-line chdir; +55;chdir.at:5;dpkg-statoverride chdir env+opt admindir;dpkg-statoverride command-line chdir; +56;chdir.at:5;dpkg-statoverride chdir env+opt root;dpkg-statoverride command-line chdir; +57;chdir.at:5;dpkg-statoverride chdir env+opt root+admindir;dpkg-statoverride command-line chdir; +58;chdir.at:329;dpkg-split chdir opts;dpkg-split command-line chdir; +59;chdir.at:329;dpkg-split chdir env;dpkg-split command-line chdir; +60;chdir.at:329;dpkg-split chdir env+opt admindir;dpkg-split command-line chdir; +61;chdir.at:329;dpkg-split chdir env+opt root;dpkg-split command-line chdir; +62;chdir.at:329;dpkg-split chdir env+opt root+admindir;dpkg-split command-line chdir; +63;chdir.at:329;dpkg-query chdir opts;dpkg-query command-line chdir; +64;chdir.at:329;dpkg-query chdir env;dpkg-query command-line chdir; +65;chdir.at:329;dpkg-query chdir env+opt admindir;dpkg-query command-line chdir; +66;chdir.at:329;dpkg-query chdir env+opt root;dpkg-query command-line chdir; +67;chdir.at:329;dpkg-query chdir env+opt root+admindir;dpkg-query command-line chdir; +68;chdir.at:329;dpkg-trigger chdir opts;dpkg-trigger command-line chdir; +69;chdir.at:329;dpkg-trigger chdir env;dpkg-trigger command-line chdir; +70;chdir.at:329;dpkg-trigger chdir env+opt admindir;dpkg-trigger command-line chdir; +71;chdir.at:329;dpkg-trigger chdir env+opt root;dpkg-trigger command-line chdir; +72;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 72; 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.22.4 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.22.4)" && + 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 10. +at_banner_text_2="Split .deb packages" +# Banner 3. testsuite.at:15 +# Category starts at test group 12. +at_banner_text_3="Resolve pathnames" +# Banner 4. testsuite.at:19 +# Category starts at test group 14. +at_banner_text_4="Diversions" +# Banner 5. testsuite.at:23 +# Category starts at test group 43. +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.22.4 test suite: dpkg tools functional test suite. ## +## --------------------------------------------------------- ##" +{ + printf "%s\n" "## --------------------------------------------------------- ## +## dpkg 1.22.4 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.22.4] $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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb old format support/' '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 -b pkg-old-templ >/dev/null + +dpkg-deb --ctrl-tarfile pkg-old-templ.deb >ctrl.tar +dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar +gzip -n ctrl.tar +gzip -n fsys.tar + +# Create deb-old 0.939 +echo '0.939000' >pkg-old.deb + + \$PERL -E 'say -s shift' \"ctrl.tar.gz\" >>pkg-old.deb +cat ctrl.tar.gz >>pkg-old.deb +cat fsys.tar.gz >>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 -b pkg-old-templ >/dev/null + +dpkg-deb --ctrl-tarfile pkg-old-templ.deb >ctrl.tar +dpkg-deb --fsys-tarfile pkg-old-templ.deb >fsys.tar +gzip -n ctrl.tar +gzip -n fsys.tar + +# Create deb-old 0.939 +echo '0.939000' >pkg-old.deb + + $PERL -E 'say -s shift' "ctrl.tar.gz" >>pkg-old.deb +cat ctrl.tar.gz >>pkg-old.deb +cat fsys.tar.gz >>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; } + + +DEB_OLD_CTRL_SIZE=$( + $PERL -E 'say -s shift' "ctrl.tar.gz" ) +DEB_OLD_FSYS_SIZE=$( + $PERL -E 'say -s shift' "fsys.tar.gz" ) +DEB_OLD_SIZE=$( + $PERL -E 'say -s shift' "pkg-old.deb" ) + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:82: +# Check old package metadata +dpkg-deb -I pkg-old.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:82" +( $at_check_trace; +# Check old package metadata +dpkg-deb -I 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" " old Debian package, version 0.939000. + size $DEB_OLD_SIZE bytes: control archive=$DEB_OLD_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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:82" +$at_failed && at_fn_log_failure +$at_traceon; } + + +DEB_OLD_0931_SIZE=$( + $PERL -E 'say -s shift' "pkg-old-0931.deb" ) +DEB_OLD_0931_CTRL_SIZE=$( + $PERL -E 'say -s shift' "ctrl-0931.tar.gz" ) + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:100: +# Check old package metadata +dpkg-deb -I pkg-old-0931.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:100" +( $at_check_trace; +# Check old package metadata +dpkg-deb -I 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" " old Debian package, version 0.931000. + size $DEB_OLD_0931_SIZE bytes: control archive=$DEB_OLD_0931_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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:100" +$at_failed && at_fn_log_failure +$at_traceon; } + + +DEB_OLD_0932_SIZE=$( + $PERL -E 'say -s shift' "pkg-old-0932.deb" ) +DEB_OLD_0932_CTRL_SIZE=$( + $PERL -E 'say -s shift' "ctrl-0932.tar.gz" ) + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:118: +# Check old package metadata +dpkg-deb -I pkg-old-0932.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:118" +( $at_check_trace; +# Check old package metadata +dpkg-deb -I 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" " old Debian package, version 0.932000. + size $DEB_OLD_0932_SIZE bytes: control archive=$DEB_OLD_0932_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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; } + + +DEB_OLD_0933_SIZE=$( + $PERL -E 'say -s shift' "pkg-old-0933.deb" ) +DEB_OLD_0933_CTRL_SIZE=$DEB_OLD_0932_CTRL_SIZE + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:136: +# Check old package metadata +dpkg-deb -I pkg-old-0933.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:136" +( $at_check_trace; +# Check old package metadata +dpkg-deb -I 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" " old Debian package, version 0.933000. + size $DEB_OLD_0933_SIZE bytes: control archive=$DEB_OLD_0933_CTRL_SIZE, main archive=$DEB_OLD_FSYS_SIZE. + 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:136" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:151: +# Check old package contents +dpkg-deb -c pkg-old.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:151" +( $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:151" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:159: +# Check old package contents +dpkg-deb -c pkg-old-0931.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:159" +( $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:159" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:167: +# Check old package contents +dpkg-deb -c pkg-old-0932.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:167" +( $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:167" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:175: +# Check old package contents +dpkg-deb -c pkg-old-0933.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:175" +( $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:175" +$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:208' \ + "dpkg-deb .deb format 2.x (core)" " " 1 +at_xfail=no +( + printf "%s\n" "3. $at_setup_line: testing $at_desc ..." + $at_traceon + + + +printf "%s\n" "deb-format.at:211" >"$at_check_line_file" +(! command -v gzip >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:211" + +: >pkg-deb-bogus-empty.deb +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:214: +# 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:214" +( $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:214" +$at_failed && at_fn_log_failure +$at_traceon; } + + +: >unknown + + + + + 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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb format support/' 'pkg-deb-format/DEBIAN/control' + + cat >pkg-deb-format/file-templ <<'_ATEOF' +test +_ATEOF + + { set +x +printf "%s\n" "$at_srcdir/deb-format.at:222: + # 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + " +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:222" +( $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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + +) >>"$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:222" +$at_failed && at_fn_log_failure +$at_traceon; } + + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:224: +# Test debian-binary with 2.x versions +echo 2.999 >debian-binary +ar qSc pkg-version-2x.deb debian-binary control.tar data.tar +ar t pkg-version-2x.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-version-2x.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:224" +( $at_check_trace; +# Test debian-binary with 2.x versions +echo 2.999 >debian-binary +ar qSc pkg-version-2x.deb debian-binary control.tar data.tar +ar t pkg-version-2x.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-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-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:224" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:246: +# Test debian-binary with extra lines +echo \"extra line\" >>debian-binary +ar qSc pkg-magic-extra.deb debian-binary control.tar data.tar +ar t pkg-magic-extra.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-magic-extra.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:246" +( $at_check_trace; +# Test debian-binary with extra lines +echo "extra line" >>debian-binary +ar qSc pkg-magic-extra.deb debian-binary control.tar data.tar +ar t pkg-magic-extra.deb +ar x pkg-templ.deb debian-binary +dpkg-deb -I pkg-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-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:246" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:268: +# 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:268" +( $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:268" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:279: +# 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:279" +( $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:279" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:290: +# 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:290" +( $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:290" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:301: +# Test duplicate debian-binary member +ar qSc pkg-duplicate-magic.deb debian-binary debian-binary control.tar data.tar +ar t pkg-duplicate-magic.deb +dpkg-deb -I pkg-duplicate-magic.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:301" +( $at_check_trace; +# Test duplicate debian-binary member +ar qSc pkg-duplicate-magic.deb debian-binary debian-binary control.tar data.tar +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:301" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:313: +# Test duplicate control member +ar qSc pkg-duplicate-control.deb debian-binary control.tar control.tar data.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:313" +( $at_check_trace; +# Test duplicate control member +ar qSc pkg-duplicate-control.deb debian-binary control.tar control.tar data.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:313" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:325: +# Test mixed member (index 1) +ar qSc pkg-mixed-1-member.deb debian-binary unknown control.tar data.tar +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:325" +( $at_check_trace; +# Test mixed member (index 1) +ar qSc pkg-mixed-1-member.deb debian-binary unknown control.tar data.tar +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:325" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:337: +# Test mixed member (index 2) +ar qSc pkg-mixed-2-member.deb debian-binary control.tar unknown data.tar +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:337" +( $at_check_trace; +# Test mixed member (index 2) +ar qSc pkg-mixed-2-member.deb debian-binary control.tar unknown data.tar +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:337" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:349: +# 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:349" +( $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:349" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:361: +# Test extra member +cp pkg-templ.deb pkg-extra-member.deb +ar qS pkg-extra-member.deb unknown +ar t pkg-extra-member.deb +dpkg-deb -I pkg-extra-member.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:361" +( $at_check_trace; +# Test extra member +cp pkg-templ.deb pkg-extra-member.deb +ar qS pkg-extra-member.deb unknown +ar t pkg-extra-member.deb +dpkg-deb -I pkg-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-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:361" +$at_failed && at_fn_log_failure +$at_traceon; } + + +: >_ignore +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:384: +# Test _ member +ar qSc pkg-under-member.deb debian-binary _ignore control.tar data.tar +ar t pkg-under-member.deb +dpkg-deb -I pkg-under-member.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:384" +( $at_check_trace; +# Test _ member +ar qSc pkg-under-member.deb debian-binary _ignore control.tar data.tar +ar t pkg-under-member.deb +dpkg-deb -I pkg-under-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-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:384" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:405: +# Test data.tar.bad member +\$PERL -E 'print \"\\0\" x 4096' >data.tar.bad +ar qSc 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:405" +( $at_check_trace; +# Test data.tar.bad member +$PERL -E 'print "\0" x 4096' >data.tar.bad +ar qSc 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:405" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:417: +# Test control.tar member +ar qSc pkg-control-none.deb debian-binary control.tar data.tar +ar t pkg-control-none.deb +dpkg-deb -I pkg-control-none.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:417" +( $at_check_trace; +# Test control.tar member +ar qSc pkg-control-none.deb debian-binary control.tar data.tar +ar t pkg-control-none.deb +dpkg-deb -I pkg-control-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 +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:417" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:437: +# Test data.tar member +ar qSc 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:437" +( $at_check_trace; +# Test data.tar member +ar qSc 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:437" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:450: +# Test data.tar.gz member +ar qSc 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:450" +( $at_check_trace; +# Test data.tar.gz member +ar qSc 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:450" +$at_failed && at_fn_log_failure +$at_traceon; } + + +# Create .deb with non-uniform data.tar/control.tar member compression +ar qSc pkg-mixed-comp.deb debian-binary control.tar data.tar.gz +DEB_MIXED_COMP_SIZE=$( + $PERL -E 'say -s shift' "pkg-mixed-comp.deb" ) + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:467: +# Test non-uniform data.tar/control.tar member compression +ar t pkg-mixed-comp.deb +dpkg-deb -I pkg-mixed-comp.deb +dpkg-deb -c pkg-mixed-comp.deb +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:467" +( $at_check_trace; +# Test non-uniform data.tar/control.tar member compression +ar t pkg-mixed-comp.deb +dpkg-deb -I pkg-mixed-comp.deb +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 +data.tar.gz + new Debian package, version 2.0. + size $DEB_MIXED_COMP_SIZE 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 +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:467" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:490: +# 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:490" +( $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:490" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:499: +# 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:499" +( $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:499" +$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-format.at:511' \ + "dpkg-deb .deb format 2.x (xz)" " " 1 +at_xfail=no +( + printf "%s\n" "4. $at_setup_line: testing $at_desc ..." + $at_traceon + + + +printf "%s\n" "deb-format.at:514" >"$at_check_line_file" +(! command -v gzip >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:514" +printf "%s\n" "deb-format.at:515" >"$at_check_line_file" +(! command -v xz >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:515" + + + + + 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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb format support/' 'pkg-deb-format/DEBIAN/control' + + cat >pkg-deb-format/file-templ <<'_ATEOF' +test +_ATEOF + + { set +x +printf "%s\n" "$at_srcdir/deb-format.at:517: + # 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + " +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:517" +( $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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + +) >>"$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:517" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:518: +# Extract the base members +xz -c control.tar >control.tar.xz +xz -c data.tar >data.tar.xz +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:518" +( $at_check_trace; +# Extract the base members +xz -c control.tar >control.tar.xz +xz -c data.tar >data.tar.xz + +) >>"$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:518" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:524: +# Test control.tar.xz member +ar qSc 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:524" +( $at_check_trace; +# Test control.tar.xz member +ar qSc 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:524" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:537: +# Test data.tar.xz member +ar qSc 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:537" +( $at_check_trace; +# Test data.tar.xz member +ar qSc 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:537" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:550: +# 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:550" +( $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:550" +$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-format.at:562' \ + "dpkg-deb .deb format 2.x (zstd)" " " 1 +at_xfail=no +( + printf "%s\n" "5. $at_setup_line: testing $at_desc ..." + $at_traceon + + + +printf "%s\n" "deb-format.at:565" >"$at_check_line_file" +(! command -v gzip >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:565" +printf "%s\n" "deb-format.at:566" >"$at_check_line_file" +(! command -v zstd >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:566" + + + + + 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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb format support/' 'pkg-deb-format/DEBIAN/control' + + cat >pkg-deb-format/file-templ <<'_ATEOF' +test +_ATEOF + + { set +x +printf "%s\n" "$at_srcdir/deb-format.at:568: + # 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + " +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:568" +( $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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + +) >>"$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:568" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:569: +# Extract the base members +zstd -c control.tar >control.tar.zst +zstd -c data.tar >data.tar.zst +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:569" +( $at_check_trace; +# Extract the base members +zstd -c control.tar >control.tar.zst +zstd -c data.tar >data.tar.zst + +) >>"$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:569" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:575: +# Test control.tar.zst member +ar qSc 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:575" +( $at_check_trace; +# Test control.tar.zst member +ar qSc 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:575" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:588: +# Test data.tar.zst member +ar qSc 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:588" +( $at_check_trace; +# Test data.tar.zst member +ar qSc 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:588" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:601: +# 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:601" +( $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:601" +$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-format.at:613' \ + "dpkg-deb .deb format 2.x (bzip2)" " " 1 +at_xfail=no +( + printf "%s\n" "6. $at_setup_line: testing $at_desc ..." + $at_traceon + + + +printf "%s\n" "deb-format.at:616" >"$at_check_line_file" +(! command -v gzip >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:616" +printf "%s\n" "deb-format.at:617" >"$at_check_line_file" +(! command -v bzip2 >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:617" + + + + + 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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb format support/' 'pkg-deb-format/DEBIAN/control' + + cat >pkg-deb-format/file-templ <<'_ATEOF' +test +_ATEOF + + { set +x +printf "%s\n" "$at_srcdir/deb-format.at:619: + # 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + " +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:619" +( $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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + +) >>"$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:619" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:620: +# Extract the base members +bzip2 -c data.tar >data.tar.bz2 +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:620" +( $at_check_trace; +# Extract the base members +bzip2 -c data.tar >data.tar.bz2 + +) >>"$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:620" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:625: +# Test data.tar.bz2 member +ar qSc 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:625" +( $at_check_trace; +# Test data.tar.bz2 member +ar qSc 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:625" +$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-format.at:641' \ + "dpkg-deb .deb format 2.x (lzma)" " " 1 +at_xfail=no +( + printf "%s\n" "7. $at_setup_line: testing $at_desc ..." + $at_traceon + + + +printf "%s\n" "deb-format.at:644" >"$at_check_line_file" +(! command -v gzip >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:644" +printf "%s\n" "deb-format.at:645" >"$at_check_line_file" +(! command -v lzma >/dev/null) \ + && at_fn_check_skip 77 "$at_srcdir/deb-format.at:645" + + + + + 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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - deb format support/' 'pkg-deb-format/DEBIAN/control' + + cat >pkg-deb-format/file-templ <<'_ATEOF' +test +_ATEOF + + { set +x +printf "%s\n" "$at_srcdir/deb-format.at:647: + # 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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + " +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:647" +( $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 -cn control.tar >control.tar.gz + gzip -cn data.tar >data.tar.gz + +) >>"$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:647" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:648: +# Extract the base members +lzma -c data.tar >data.tar.lzma +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-format.at:648" +( $at_check_trace; +# Extract the base members +lzma -c data.tar >data.tar.lzma + +) >>"$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:648" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-format.at:653: +# Test data.tar.lzma member +ar qSc 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:653" +( $at_check_trace; +# Test data.tar.lzma member +ar qSc 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:653" +$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 'deb-content.at:1' \ + "dpkg-deb .deb conffiles" " " 1 +at_xfail=no +( + printf "%s\n" "8. $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_8 +#AT_START_9 +at_fn_group_banner 9 'deb-fields.at:1' \ + "dpkg-deb .deb fields" " " 1 +at_xfail=no +( + printf "%s\n" "9. $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 + + + + $PERL -p -i -E 's/^Package: .*$/$&\nPackage-Type: udeb/' 'pkg-package-type-use/DEBIAN/control' + +{ set +x +printf "%s\n" "$at_srcdir/deb-fields.at:14: +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:14" +( $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:14" +$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 + + + + $PERL -p -i -E 's/^Priority:/Class:/' 'pkg-obsolete-fields/DEBIAN/control' + + + $PERL -p -i -E 's/^Version: 0.0-1$/Version: 0.0/' 'pkg-obsolete-fields/DEBIAN/control' + + + $PERL -p -i -E 's/^Version:.*$/$&\nRevision: 1/' 'pkg-obsolete-fields/DEBIAN/control' + + + $PERL -p -i -E 's/^Package:.*$/$&\nOptional: suggests/' 'pkg-obsolete-fields/DEBIAN/control' + + + $PERL -p -i -E 's/^Package:.*$/$&\nRecommended: recommends/' 'pkg-obsolete-fields/DEBIAN/control' + +{ set +x +printf "%s\n" "$at_srcdir/deb-fields.at:31: +dpkg-deb -b pkg-obsolete-fields +" +at_fn_check_prepare_notrace 'an embedded newline' "deb-fields.at:31" +( $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:31" +$at_failed && at_fn_log_failure +$at_traceon; } + +{ set +x +printf "%s\n" "$at_srcdir/deb-fields.at:44: +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:44" +( $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:44" +$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 'deb-split.at:1' \ + "dpkg-split options" " " 2 +at_xfail=no +( + printf "%s\n" "10. $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_10 +#AT_START_11 +at_fn_group_banner 11 'deb-split.at:9' \ + "dpkg-split .deb format" " " 2 +at_xfail=no +( + printf "%s\n" "11. $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 + + + + $PERL -p -i -E 's/^Description:.*$/$& - normal package to be split/' '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 1 2 3 4 5 6 7 8 9 10 ; do + test -f pkg-split-part.\${p}of10.deb +done +ar x pkg-split-part.1of10.deb data.1 +" +at_fn_check_prepare_notrace 'a ${...} parameter expansion' "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 1 2 3 4 5 6 7 8 9 10 ; do + test -f pkg-split-part.${p}of10.deb +done +ar x pkg-split-part.1of10.deb data.1 + +) >>"$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:42: +# Test debian-split with 2.x version +ar x pkg-split-part.1of10.deb debian-split +\$PERL -p -i -E 's/.*/2.999/ if \$. == 1' debian-split +ar qSc pkg-split-part-version-2x.deb debian-split data.1 +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:42" +( $at_check_trace; +# Test debian-split with 2.x version +ar x pkg-split-part.1of10.deb debian-split +$PERL -p -i -E 's/.*/2.999/ if $. == 1' debian-split +ar qSc pkg-split-part-version-2x.deb debian-split data.1 +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:42" +$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:68: +# Test debian-split with extra lines +ar x pkg-split-part.1of10.deb debian-split +echo \"extra line\" >>debian-split +ar qSc pkg-split-part-magic-extra.deb debian-split data.1 +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:68" +( $at_check_trace; +# Test debian-split with extra lines +ar x pkg-split-part.1of10.deb debian-split +echo "extra line" >>debian-split +ar qSc pkg-split-part-magic-extra.deb debian-split data.1 +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:68" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:92: +# 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:92" +( $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:92" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:102: +# 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:102" +( $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:102" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:112: +# Test duplicate debian-split member +ar x pkg-split-part.1of10.deb debian-split data.1 +ar qSc pkg-split-part-duplicate-magic.deb debian-split debian-split data.1 +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:112" +( $at_check_trace; +# Test duplicate debian-split member +ar x pkg-split-part.1of10.deb debian-split data.1 +ar qSc pkg-split-part-duplicate-magic.deb debian-split debian-split data.1 +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:112" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:124: +# Test unknown extra member +cp pkg-split-part.1of10.deb pkg-split-part-extra-member.deb +echo \"some content\" >unknown +ar qS 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:124" +( $at_check_trace; +# Test unknown extra member +cp pkg-split-part.1of10.deb pkg-split-part-extra-member.deb +echo "some content" >unknown +ar qS 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:124" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:149: +# 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:149" +( $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:149" +$at_failed && at_fn_log_failure +$at_traceon; } + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:166: +# 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:166" +( $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:166" +$at_failed && at_fn_log_failure +$at_traceon; } + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:183: +# 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:183" +( $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:183" +$at_failed && at_fn_log_failure +$at_traceon; } + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:200: +# 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:200" +( $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:200" +$at_failed && at_fn_log_failure +$at_traceon; } + + +{ set +x +printf "%s\n" "$at_srcdir/deb-split.at:218: +# 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:218" +( $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:218" +$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 'realpath.at:1' \ + "dpkg-realpath options" " " 3 +at_xfail=no +( + printf "%s\n" "12. $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_12 +#AT_START_13 +at_fn_group_banner 13 'realpath.at:9' \ + "dpkg-realpath path resolving" " " 3 +at_xfail=no +( + printf "%s\n" "13. $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 -sf aa/bb/cc/file zz/yy/xx/symlink-rel +ln -sf /aa/bb/cc/file zz/yy/xx/symlink-abs +: >usr/bin/a-shell +ln -sf /usr/bin/a-shell usr/bin/sh + +tmpdir="$( $PERL -MCwd=realpath,getcwd -E 'say realpath(getcwd())')" +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_13 +#AT_START_14 +at_fn_group_banner 14 'divert.at:1' \ + "dpkg-divert options" " " 4 +at_xfail=no +( + printf "%s\n" "14. $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: \$EGREP -q '(takes a value|needs.*argument)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:10" +( $at_check_trace; $EGREP -q '(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_dynamic "$GREP -q 'unknown option' stderr" "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: \$EGREP -q '(conflicting|two).*remove.*add.*' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:16" +( $at_check_trace; $EGREP -q '(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: \$EGREP -q '(takes a value|needs.*argument)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:19" +( $at_check_trace; $EGREP -q '(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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'newline' stderr" "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: \$EGREP -q '(takes a value|needs.*argument)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:29" +( $at_check_trace; $EGREP -q '(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_dynamic "$GREP -q 'newline' stderr" "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_dynamic "$GREP -q 'needs a single argument' stderr" "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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'newline' stderr" "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: \$EGREP -q 'director(y|ies)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:46" +( $at_check_trace; $EGREP -q '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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'needs a single argument' stderr" "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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'newline' stderr" "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_dynamic "$GREP -q 'needs a single argument' stderr" "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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'newline' stderr" "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_dynamic "$GREP -q 'needs a single argument' stderr" "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_dynamic "$GREP -q 'absolute' stderr" "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_dynamic "$GREP -q 'newline' stderr" "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_14 +#AT_START_15 +at_fn_group_banner 15 'divert.at:83' \ + "dpkg-divert query (empty db)" " " 4 +at_xfail=no +( + printf "%s\n" "15. $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_15 +#AT_START_16 +at_fn_group_banner 16 'divert.at:94' \ + "dpkg-divert query (list)" " " 4 +at_xfail=no +( + printf "%s\n" "16. $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_16 +#AT_START_17 +at_fn_group_banner 17 'divert.at:134' \ + "dpkg-divert query (listpackage + truename)" " " 4 +at_xfail=no +( + printf "%s\n" "17. $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_17 +#AT_START_18 +at_fn_group_banner 18 'divert.at:160' \ + "dpkg-divert add (local rename)" " " 4 +at_xfail=no +( + printf "%s\n" "18. $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_dynamic "$GREP -q \"Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib\" stdout" "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_18 +#AT_START_19 +at_fn_group_banner 19 'divert.at:178' \ + "dpkg-divert add (local no-rename)" " " 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: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_dynamic "$GREP -q \"Adding.*local.*diversion.* /testdir/foo.* /testdir/foo.distrib\" stdout" "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_19 +#AT_START_20 +at_fn_group_banner 20 'divert.at:196' \ + "dpkg-divert add (rename quiet)" " " 4 +at_xfail=no +( + printf "%s\n" "20. $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_20 +#AT_START_21 +at_fn_group_banner 21 'divert.at:213' \ + "dpkg-divert add (test rename quiet)" " " 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 + + + 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_21 +#AT_START_22 +at_fn_group_banner 22 'divert.at:226' \ + "dpkg-divert add (rename missing quiet)" " " 4 +at_xfail=no +( + printf "%s\n" "22. $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_22 +#AT_START_23 +at_fn_group_banner 23 'divert.at:243' \ + "dpkg-divert add (local rename quiet)" " " 4 +at_xfail=no +( + printf "%s\n" "23. $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_23 +#AT_START_24 +at_fn_group_banner 24 'divert.at:260' \ + "dpkg-divert add (package rename quiet)" " " 4 +at_xfail=no +( + printf "%s\n" "24. $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_24 +#AT_START_25 +at_fn_group_banner 25 'divert.at:274' \ + "dpkg-divert add (rename self-link)" " " 4 +at_xfail=no +( + printf "%s\n" "25. $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_25 +#AT_START_26 +at_fn_group_banner 26 'divert.at:292' \ + "dpkg-divert add (rename other-file)" " " 4 +at_xfail=no +( + printf "%s\n" "26. $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_dynamic "$GREP -q 'error: rename involves overwriting' stderr" "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_26 +#AT_START_27 +at_fn_group_banner 27 'divert.at:305' \ + "dpkg-divert add (rename missing dir)" " " 4 +at_xfail=no +( + printf "%s\n" "27. $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_27 +#AT_START_28 +at_fn_group_banner 28 'divert.at:319' \ + "dpkg-divert add (rename read-only dir)" " " 4 +at_xfail=no +( + printf "%s\n" "28. $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_dynamic "$GREP -q 'error: .* Permission denied' stderr" "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_dynamic "$GREP -q 'error: .* Permission denied' stderr" "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_28 +#AT_START_29 +at_fn_group_banner 29 'divert.at:343' \ + "dpkg-divert add (rename no-access dir)" " " 4 +at_xfail=no +( + printf "%s\n" "29. $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_dynamic "$GREP -q 'error: .* Permission denied' stderr" "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_dynamic "$GREP -q 'error: .* Permission denied' stderr" "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_29 +#AT_START_30 +at_fn_group_banner 30 'divert.at:367' \ + "dpkg-divert add second diversion" " " 4 +at_xfail=no +( + printf "%s\n" "30. $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_dynamic "$GREP -q 'Adding' stdout" "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_dynamic "$GREP -q 'Leaving' stdout" "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_dynamic "$GREP -q 'Leaving' stdout" "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_dynamic "$GREP -q 'clashes' stderr" "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_dynamic "$GREP -q 'clashes' stderr" "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_dynamic "$GREP -q 'clashes' stderr" "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_dynamic "$GREP -q 'clashes' stderr" "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_dynamic "$GREP -q 'clashes' stderr" "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_30 +#AT_START_31 +at_fn_group_banner 31 'divert.at:401' \ + "dpkg-divert add third diversion" " " 4 +at_xfail=no +( + printf "%s\n" "31. $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_dynamic "$GREP -q 'Adding' stdout" "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_dynamic "$GREP -q 'Adding' stdout" "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_dynamic "$GREP -q 'Leaving' stdout" "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_dynamic "$GREP -q 'clashes' stderr" "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_31 +#AT_START_32 +at_fn_group_banner 32 'divert.at:420' \ + "dpkg-divert add (file owned by --package)" " " 4 +at_xfail=no +( + printf "%s\n" "32. $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_32 +#AT_START_33 +at_fn_group_banner 33 'divert.at:447' \ + "dpkg-divert remove (missing)" " " 4 +at_xfail=no +( + printf "%s\n" "33. $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_dynamic "$GREP -q 'No diversion' stdout" "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_33 +#AT_START_34 +at_fn_group_banner 34 'divert.at:459' \ + "dpkg-divert remove (divert-to)" " " 4 +at_xfail=no +( + printf "%s\n" "34. $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_dynamic "$GREP -q 'mismatch on divert-to' stderr" "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_dynamic "$GREP -q 'mismatch on package' stderr" "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: \$EGREP -q 'mismatch on (package|divert-to)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:484" +( $at_check_trace; $EGREP -q '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: \$EGREP -q 'Removing .*/testdir/foo' stdout" +at_fn_check_prepare_dynamic "$EGREP -q 'Removing .*/testdir/foo' stdout" "divert.at:488" +( $at_check_trace; $EGREP -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: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_34 +#AT_START_35 +at_fn_group_banner 35 'divert.at:494' \ + "dpkg-divert remove (plain)" " " 4 +at_xfail=no +( + printf "%s\n" "35. $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: \$EGREP -q 'Removing .* /testdir/bar' stdout" +at_fn_check_prepare_dynamic "$EGREP -q 'Removing .* /testdir/bar' stdout" "divert.at:511" +( $at_check_trace; $EGREP -q '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_35 +#AT_START_36 +at_fn_group_banner 36 'divert.at:517' \ + "dpkg-divert remove (by-package)" " " 4 +at_xfail=no +( + printf "%s\n" "36. $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_36 +#AT_START_37 +at_fn_group_banner 37 'divert.at:539' \ + "dpkg-divert remove (test)" " " 4 +at_xfail=no +( + printf "%s\n" "37. $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_dynamic "$GREP -q 'Removing .*/testdir/foo' stdout" "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_37 +#AT_START_38 +at_fn_group_banner 38 'divert.at:564' \ + "dpkg-divert db (no-access)" " " 4 +at_xfail=no +( + printf "%s\n" "38. $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: \$EGREP -q '(cannot|failed).*open' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:575" +( $at_check_trace; $EGREP -q '(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_38 +#AT_START_39 +at_fn_group_banner 39 'divert.at:580' \ + "dpkg-divert db (truncated)" " " 4 +at_xfail=no +( + printf "%s\n" "39. $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: \$EGREP -q '(corrupt|unexpected end of file)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:587" +( $at_check_trace; $EGREP -q '(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: \$EGREP -q '(corrupt|unexpected end of file)' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:594" +( $at_check_trace; $EGREP -q '(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_39 +#AT_START_40 +at_fn_group_banner 40 'divert.at:598' \ + "dpkg-divert db (read-only dir)" " " 4 +at_xfail=no +( + printf "%s\n" "40. $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_dynamic "$GREP -q 'Adding' stdout" "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_dynamic "$GREP -q 'create.*new' stderr" "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_40 +#AT_START_41 +at_fn_group_banner 41 'divert.at:613' \ + "dpkg-divert db (disk full)" " " 4 +at_xfail=no +( + printf "%s\n" "41. $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_dynamic "$GREP -q 'Adding' stdout" "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: \$EGREP -q '(write|flush|close).*new' stderr" +at_fn_check_prepare_notrace 'a shell pipeline' "divert.at:624" +( $at_check_trace; $EGREP -q '(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_41 +#AT_START_42 +at_fn_group_banner 42 'divert.at:628' \ + "dpkg-divert db (pathname is dir)" " " 4 +at_xfail=no +( + printf "%s\n" "42. $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_dynamic "$GREP -q 'Adding' stdout" "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_dynamic "$GREP -q 'remov.*old' stderr" "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_42 +#AT_START_43 +at_fn_group_banner 43 'chdir.at:5' \ + "dpkg chdir opts" " " 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_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_43 +#AT_START_44 +at_fn_group_banner 44 'chdir.at:5' \ + "dpkg chdir env" " " 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_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_44 +#AT_START_45 +at_fn_group_banner 45 'chdir.at:5' \ + "dpkg chdir env+opt admindir" " " 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 --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_45 +#AT_START_46 +at_fn_group_banner 46 'chdir.at:5' \ + "dpkg chdir env+opt root" " " 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_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_46 +#AT_START_47 +at_fn_group_banner 47 'chdir.at:5' \ + "dpkg chdir env+opt root+admindir" " " 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_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_47 +#AT_START_48 +at_fn_group_banner 48 'chdir.at:5' \ + "dpkg-divert chdir opts" " " 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_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_48 +#AT_START_49 +at_fn_group_banner 49 'chdir.at:5' \ + "dpkg-divert chdir env" " " 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_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_49 +#AT_START_50 +at_fn_group_banner 50 'chdir.at:5' \ + "dpkg-divert chdir env+opt admindir" " " 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-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_50 +#AT_START_51 +at_fn_group_banner 51 'chdir.at:5' \ + "dpkg-divert chdir env+opt root" " " 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_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_51 +#AT_START_52 +at_fn_group_banner 52 'chdir.at:5' \ + "dpkg-divert chdir env+opt root+admindir" " " 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_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_52 +#AT_START_53 +at_fn_group_banner 53 'chdir.at:5' \ + "dpkg-statoverride chdir opts" " " 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_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_53 +#AT_START_54 +at_fn_group_banner 54 'chdir.at:5' \ + "dpkg-statoverride chdir env" " " 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: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_54 +#AT_START_55 +at_fn_group_banner 55 'chdir.at:5' \ + "dpkg-statoverride chdir env+opt admindir" " " 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: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_55 +#AT_START_56 +at_fn_group_banner 56 'chdir.at:5' \ + "dpkg-statoverride chdir env+opt root" " " 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: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_56 +#AT_START_57 +at_fn_group_banner 57 'chdir.at:5' \ + "dpkg-statoverride chdir env+opt root+admindir" " " 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: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_57 +#AT_START_58 +at_fn_group_banner 58 'chdir.at:329' \ + "dpkg-split chdir opts" " " 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_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_58 +#AT_START_59 +at_fn_group_banner 59 'chdir.at:329' \ + "dpkg-split chdir env" " " 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_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_59 +#AT_START_60 +at_fn_group_banner 60 'chdir.at:329' \ + "dpkg-split chdir env+opt admindir" " " 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-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_60 +#AT_START_61 +at_fn_group_banner 61 'chdir.at:329' \ + "dpkg-split chdir env+opt root" " " 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_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_61 +#AT_START_62 +at_fn_group_banner 62 'chdir.at:329' \ + "dpkg-split chdir env+opt root+admindir" " " 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_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_62 +#AT_START_63 +at_fn_group_banner 63 'chdir.at:329' \ + "dpkg-query chdir opts" " " 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_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_63 +#AT_START_64 +at_fn_group_banner 64 'chdir.at:329' \ + "dpkg-query chdir env" " " 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_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_64 +#AT_START_65 +at_fn_group_banner 65 'chdir.at:329' \ + "dpkg-query chdir env+opt admindir" " " 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-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_65 +#AT_START_66 +at_fn_group_banner 66 'chdir.at:329' \ + "dpkg-query chdir env+opt root" " " 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_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_66 +#AT_START_67 +at_fn_group_banner 67 'chdir.at:329' \ + "dpkg-query chdir env+opt root+admindir" " " 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_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_67 +#AT_START_68 +at_fn_group_banner 68 'chdir.at:329' \ + "dpkg-trigger chdir opts" " " 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_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_68 +#AT_START_69 +at_fn_group_banner 69 'chdir.at:329' \ + "dpkg-trigger chdir env" " " 5 +at_xfail=no +( + printf "%s\n" "69. $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_69 +#AT_START_70 +at_fn_group_banner 70 'chdir.at:329' \ + "dpkg-trigger chdir env+opt admindir" " " 5 +at_xfail=no +( + printf "%s\n" "70. $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_70 +#AT_START_71 +at_fn_group_banner 71 'chdir.at:329' \ + "dpkg-trigger chdir env+opt root" " " 5 +at_xfail=no +( + printf "%s\n" "71. $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_71 +#AT_START_72 +at_fn_group_banner 72 'chdir.at:329' \ + "dpkg-trigger chdir env+opt root+admindir" " " 5 +at_xfail=no +( + printf "%s\n" "72. $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_72 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..c4401f0 --- /dev/null +++ b/src/common/force.c @@ -0,0 +1,405 @@ +/* + * 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 struct forceinfo *fip; + + if (strcmp(value, "help") == 0) { + char *force_string = get_force_string(); + + printf(_( +"%s forcing options - control behavior 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 (;;) { + const char *comma; + size_t l; + + 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..c232c7f --- /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 DPKG_ATTR_ENUM_FLAGS 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..597872b --- /dev/null +++ b/src/deb/build.c @@ -0,0 +1,729 @@ +/* + * 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 (!opt_nocheck && 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 (opt_nocheck) { + 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 = compress_params_deb0; + + 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..eafb5b7 --- /dev/null +++ b/src/deb/dpkg-deb.h @@ -0,0 +1,89 @@ +/* + * 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 opt_debug; +extern int opt_nocheck; +extern const char *opt_showformat; + +extern struct deb_version deb_format; + +enum DPKG_ATTR_ENUM_FLAGS 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 struct compress_params compress_params_deb0; +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..8b78a7e --- /dev/null +++ b/src/deb/extract.c @@ -0,0 +1,508 @@ +/* + * 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 nread; + char *nl; + + nread = fd_read(fd, buf + line_size, n); + if (nread <= 0) + return nread; + + nl = memchr(buf + line_size, '\n', nread); + line_size += nread; + + 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 rc; + int dummy; + pid_t c1=0,c2,c3; + int p1[2], p2[2]; + int p2_out; + char nlc; + struct compress_params decompress_params = { + .type = COMPRESSOR_TYPE_GZIP, + .threads_max = compress_params.threads_max, + }; + + ar = dpkg_ar_open(debar); + + rc = read_line(ar->fd, versionbuf, strlen(DPKG_AR_MAGIC), sizeof(versionbuf) - 1); + if (rc <= 0) + read_fail(rc, debar, _("archive magic version number")); + + if (strcmp(versionbuf, DPKG_AR_MAGIC) == 0) { + int adminmember = -1; + bool header_done = false; + + ctrllennum= 0; + for (;;) { + struct dpkg_ar_hdr arh; + + rc = fd_read(ar->fd, &arh, sizeof(arh)); + if (rc != sizeof(arh)) + read_fail(rc, 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); + rc = fd_read(ar->fd, infobuf, memberlen + (memberlen & 1)); + if (rc != (memberlen + (memberlen & 1))) + read_fail(rc, 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); + + rc = read_line(ar->fd, ctrllenbuf, 1, sizeof(ctrllenbuf) - 1); + if (rc <= 0) + read_fail(rc, 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); + dpkg_ar_close(ar); + 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 behavior 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..6598663 --- /dev/null +++ b/src/deb/info.c @@ -0,0 +1,341 @@ +/* + * 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 re= 0; + + while ((component = *argv++) != NULL) { + int fd; + + 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 char * +info_interpreter(FILE *cc, int *lines) +{ + char interpreter[INTERPRETER_MAX + 1]; + int c; + + *lines = 0; + interpreter[0] = '\0'; + if (getc(cc) == '#' && getc(cc) == '!') { + char *p; + int il; + + 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)++; + } + + return m_strdup(interpreter); +} + +static void +info_list(const char *debar, const char *dir) +{ + struct varbuf controlfile = VARBUF_INIT; + struct dirent **cdlist; + int cdn, n; + FILE *cc; + + cdn = scandir(dir, &cdlist, &ilist_select, alphasort); + if (cdn == -1) + ohshite(_("cannot scan directory '%.255s'"), dir); + + for (n = 0; n < cdn; n++) { + struct dirent *cdep; + struct stat stab; + + 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)) { + int exec_mark = (S_IXUSR & stab.st_mode) ? '*' : ' '; + char *interpreter; + int lines; + + cc = fopen(controlfile.buf, "r"); + if (!cc) + ohshite(_("cannot open '%.255s' (in '%.255s')"), cdep->d_name, dir); + + interpreter = info_interpreter(cc, &lines); + + if (ferror(cc)) + ohshite(_("failed to read '%.255s' (in '%.255s')"), cdep->d_name, dir); + fclose(cc); + if (str_is_set(interpreter)) + printf(_(" %7jd bytes, %5d lines %c %-20.127s %.127s\n"), + (intmax_t)stab.st_size, lines, exec_mark, cdep->d_name, + interpreter); + else + printf(_(" %7jd bytes, %5d lines %c %.127s\n"), + (intmax_t)stab.st_size, lines, exec_mark, cdep->d_name); + + free(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 { + int lines, c; + + 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; + + varbuf_reset(&str); + field = find_field_info(fieldinfos, fields[i]); + if (field) { + field->wcall(&str, pkg, &pkg->available, fieldflags, field); + } else { + const struct arbitraryfield *arbfield; + + 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(opt_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..0217278 --- /dev/null +++ b/src/deb/main.c @@ -0,0 +1,325 @@ +/* + * 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 *opt_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 opt_debug = 0; +int opt_nocheck = 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_deb0 = { + .type = COMPRESSOR_TYPE_GZIP, + .strategy = COMPRESSOR_STRATEGY_NONE, + .level = -1, + .threads_max = -1, +}; + +struct compress_params compress_params = { + .type = 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, &opt_debug, NULL, NULL, 1 }, + { "verbose", 'v', 0, &opt_verbose, NULL, NULL, 1 }, + { "nocheck", 0, 0, &opt_nocheck, 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, &opt_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 && deb_format.major == 0) + badusage(_("unsupported deb format '%d.%d' with non-uniform compression"), + deb_format.major, deb_format.minor); + + if (deb_format.major == 0) + compress_params = compress_params_deb0; + + 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..23a0cd0 --- /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, FHFF_NONE); + + /* 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, FHFF_NONE); + + /* 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_NO_NEW); + + 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_NO_NEW); + + /* 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_NO_NEW); + + /* 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..619f489 --- /dev/null +++ b/src/dpkg-db-backup.sh @@ -0,0 +1,87 @@ +#!/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}" +TAR="${TAR:-tar}" + +# 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-db-keeper.sh b/src/dpkg-db-keeper.sh new file mode 100755 index 0000000..8c99a4c --- /dev/null +++ b/src/dpkg-db-keeper.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Copyright © 2023 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 + +PKGDATADIR_DEFAULT=src +PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}" + +# shellcheck source=src/sh/dpkg-error.sh +. "$PKGDATADIR/sh/dpkg-error.sh" + +setup_colors + +# This script is used to track any change in the dpkg database for later +# inspection, either as a matter of record tracking or to aid in debugging +# dpkg behavior. It can be installed as a post-invoke hook such as: +# +# ,--- /etc/dpkg/dpkg.cfg.d/db-keeper --- +# post-invoke "/usr/libexec/dpkg-db-keeper" +# `--- + +if [ -n "$DPKG_ROOT" ]; then + # Only operate on the main system. + exit 0 +fi + +if ! command -v git >/dev/null; then + # Do nothing if there is no git. + exit 0 +fi + +: "${DPKG_ADMINDIR:=/var/lib/dpkg}" + +cd "$DPKG_ADMINDIR" || exit 0 + +if [ ! -e .git ]; then + # Initialize the git repo. + git init +fi + +git add -A +git commit -m 'Commit dpkg db updates' + +exit 0 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..015bb23 --- /dev/null +++ b/src/main/archives.c @@ -0,0 +1,1711 @@ +/* + * 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; + } + + /* cppcheck-suppress[nullPointerArithmetic]: + * False positive, imported module. */ + 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) { + /* cppcheck-suppress[nullPointerArithmetic,pointerLessThanZero]: + * False positive, imported module. */ + 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 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) { + struct pkgset *divpkgset; + + 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; + + debug(dbg_eachfiledetail,"filesavespackage ... is 3rd package"); + + /* If !files_list_valid then we have already disappeared this one, + * so we should not try to make it take over this shared directory. */ + 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 n; + + n = fd_read(tc->backendpipe, buf, len); + if (n < 0) + ohshite(_("error reading from dpkg-deb pipe")); + return n; +} + +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; + + if (fd_skip(tc->backendpipe, ti->size, &err) < 0) + ohshit(_("cannot skip file '%.255s' (replaced or excluded?) from pipe: %s"), + ti->name, 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 *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"), + te->name, fnamenewvb.buf, 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_set_str(&hardlinkfn, dpkg_fsys_get_dir()); + linknode = fsys_hash_find_node(te->linkname, FHFF_NONE); + 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 *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"), + te->name, 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, FHFF_NONE); + 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; + + 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? */ + if (ti->linkname[0] == '/') { + varbuf_set_str(symlinkfn, dpkg_fsys_get_dir()); + } else { + const char *lastslash; + + lastslash= strrchr(fname, '/'); + if (lastslash == NULL) + internerr("tar entry filename '%s' does not contain '/'", fname); + varbuf_set_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; + 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, FHFF_NONE); + + 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)) { + /* Trying to remove a directory or a file on a read-only filesystem, + * even if non-existent, always returns EROFS. */ + if (errno == EROFS) { + /* If the file does not exist the access() function will remap the + * EROFS into an ENOENT, otherwise restore EROFS to fail with that. */ + if (access(fnametmpvb.buf, F_OK) == 0) + errno = EROFS; + } + + 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)) { + ssize_t symlink_len; + 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); + symlink_len = readlink(fnamevb.buf, symlinkfn.buf, symlinkfn.size); + if (symlink_len < 0) + ohshite(_("unable to read link '%.255s'"), ti->name); + else if (symlink_len > stab.st_size) + ohshit(_("symbolic link '%.250s' size has changed from %jd to %zd"), + fnamevb.buf, (intmax_t)stab.st_size, symlink_len); + else if (symlink_len < stab.st_size) + warning(_("symbolic link '%.250s' size has changed from %jd to %zd"), + fnamevb.buf, (intmax_t)stab.st_size, symlink_len); + varbuf_trunc(&symlinkfn, symlink_len); + 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, DEBEXT) != 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..0f7d6ff --- /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]; + const 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..c2d58c7 --- /dev/null +++ b/src/main/configure.c @@ -0,0 +1,825 @@ +/* + * 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 DPKG_ATTR_ENUM_FLAGS 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_NO_COPY), + pkg, &pkg->installed); + + rc = conffderef(pkg, &cdr, usenode->name); + if (rc == -1) { + conff->hash = EMPTYHASHFLAG; + return; + } + md5hash(pkg, currenthash, cdr.buf); + + varbuf_set_varbuf(&cdr2, &cdr); + /* 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_set_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_set_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_varbuf(result, &target); + 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..e8efdd3 --- /dev/null +++ b/src/main/depcon.c @@ -0,0 +1,705 @@ +/* + * 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; + + /* 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 { + int nconflicts; + + /* 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= §ionentries; + *sep && strcasecmp(thissect,(*sep)->name) > 0; + sep= &(*sep)->next); + se->name= thissect; + se->count= 0; + se->next= *sep; + *sep= se; + sects++; + } + se->count++; totalcount++; + } + 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..59e730e --- /dev/null +++ b/src/main/help.c @@ -0,0 +1,325 @@ +/* + * 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/command.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; +} + +/** + * Verify that some programs can be found in the PATH. + */ +void checkpath(void) { + static const char *const prog_list[] = { + DPKG_DEFAULT_SHELL, + RM, + TAR, + DIFF, + BACKEND, + /* macOS 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 (!command_in_path(*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; + + for (conff = pkg->installed.conffiles; conff; conff = conff->next) { + struct fsys_namenode *namenode; + + namenode = fsys_hash_find_node(conff->name, FHFF_NONE); /* 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..02887c2 --- /dev/null +++ b/src/main/main.c @@ -0,0 +1,781 @@ +/* + * 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; + + if (*value == 'h') { + const struct debuginfo *dip; + + 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); + + lno = 0; + + for (;;) { + bool mode = false; + int argc= 1; + + 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..f841e8d --- /dev/null +++ b/src/main/main.h @@ -0,0 +1,304 @@ +/* + * 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); +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..aba9ba7 --- /dev/null +++ b/src/main/packages.c @@ -0,0 +1,760 @@ +/* + * 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 (without --pending) 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; + 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)) { + struct pkginfo *volatile pkg; + + 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_varbuf(aemsgs, &oemsgs); + } 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..88c01a2 --- /dev/null +++ b/src/main/remove.c @@ -0,0 +1,686 @@ +/* + * 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_set_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_set_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, FHFF_NONE); + 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..d71202e --- /dev/null +++ b/src/main/select.c @@ -0,0 +1,244 @@ +/* + * 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; + int i; + + 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 { + const char *thisarg; + + while ((thisarg= *argv++)) { + struct pkg_spec pkgspec; + int found; + + 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..125eb02 --- /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; + + 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) { + struct pkginfo *gaveup; + struct trigpend *tp; + 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..02c2681 --- /dev/null +++ b/src/main/unpack.c @@ -0,0 +1,1734 @@ +/* + * 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/command.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 (!command_in_path(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, FHFF_NONE); + 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_set_varbuf(&cdrext, &cdr); + 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_set_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 *dep; + 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) { + struct deppossi **newpossilastp, *possi; + struct dependency *newdep; + + newdep = nfmalloc(sizeof(*newdep)); + newdep->up = pkg; + newdep->next = NULL; + newdep->list = NULL; + newpossilastp = &newdep->list; + + for (possi = dep->list; possi; possi = possi->next) { + struct deppossi *newpossi; + + 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..6a5d733 --- /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) +{ + static int fd; + + fd = open(filename, O_RDONLY); + + if (fd >= 0) { + struct dpkg_error err; + char hash[MD5HASHLEN + 1]; + + 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_set_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..7f8de59 --- /dev/null +++ b/src/query/main.c @@ -0,0 +1,887 @@ +/* + * 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 *opt_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; + 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) { + int i; + + for (i = 0; i < array.n_pkgs; i++) { + struct pkginfo *pkg; + + 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) +{ + const char *thisarg; + 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) { + struct fsys_namenode *namenode; + int 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_set_str(&path, thisarg); + varbuf_trunc(&path, path_trim_slash_slashdot(path.buf)); + + namenode = fsys_hash_find_node(path.buf, FHFF_NONE); + found += searchoutput(namenode); + } else { + struct fsys_hash_iter *iter; + + 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) +{ + int failures = 0; + + modstatdb_open(msdbrw_readonly); + + if (!*argv) { + writedb_stanzas(stdout, _("<standard output>"), 0); + } else { + const char *thisarg; + + while ((thisarg = *argv++) != NULL) { + struct pkginfo *pkg; + + 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) +{ + int failures = 0; + + modstatdb_open(msdbrw_readonly | msdbrw_available_readonly); + + if (!*argv) { + writedb_stanzas(stdout, _("<standard output>"), wdb_dump_available); + } else { + const char *thisarg; + + while ((thisarg = *argv++) != NULL) { + struct pkginfo *pkg; + + 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 pkg_format_node *fmt; + bool fmt_needs_db_fsys; + int rc = 0; + + fmt = pkg_format_parse(opt_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) { + int i; + + if (fmt_needs_db_fsys) + ensure_allinstfiles_available_quiet(); + for (i = 0; i < array.n_pkgs; i++) { + struct pkginfo *pkg; + + 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, &opt_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='[0m' +COLOR_BOLD='[1m' +COLOR_BLACK='[30m' +COLOR_RED='[31m' +COLOR_GREEN='[32m' +COLOR_YELLOW='[33m' +COLOR_BLUE='[34m' +COLOR_MAGENTA='[35m' +COLOR_CYAN='[36m' +COLOR_WHITE='[37m' +COLOR_BOLD_BLACK='[1;30m' +COLOR_BOLD_RED='[1;31m' +COLOR_BOLD_GREEN='[1;32m' +COLOR_BOLD_YELLOW='[1;33m' +COLOR_BOLD_BLUE='[1;34m' +COLOR_BOLD_MAGENTA='[1;35m' +COLOR_BOLD_CYAN='[1;36m' +COLOR_BOLD_WHITE='[1;37m' + +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..7fe9a08 --- /dev/null +++ b/src/split/info.c @@ -0,0 +1,292 @@ +/* + * 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 ret; + char *endp; + + errno = 0; + ret = strtoimax(value, &endp, 10); + if (value == endp || *endp) + ohshit(_("file '%.250s' is corrupt - bad digit (code %d) in %s"), + fn, *endp, what); + if (ret < 0 || errno == ERANGE) + ohshit(_("file '%s' is corrupt; out of range integer in %s"), fn, what); + + return ret; +} + +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 struct varbuf format_member = VARBUF_INIT; + + 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); + + varbuf_reset(&format_member); + varbuf_grow(&format_member, thisilen + 2); + + rc = fd_read(ar->fd, format_member.buf, thisilen + (thisilen & 1)); + if (rc != (ssize_t)(thisilen + (thisilen & 1))) + read_fail(rc, ar->name, "reading header member"); + if (thisilen & 1) { + int c = format_member.buf[thisilen]; + + if (c != '\n') + ohshit(_("file '%.250s' is corrupt - bad padding character (code %d)"), + ar->name, c); + } + varbuf_trunc(&format_member, thisilen); + if (memchr(format_member.buf, 0, thisilen)) + ohshit(_("file '%.250s' is corrupt - nulls in info section"), ar->name); + + ir->filename = ar->name; + + rip = format_member.buf; + 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; + + if (!*argv) + badusage(_("--%s requires one or more part file arguments"), + cipaction->olong); + + while ((thisarg= *argv++)) { + struct partinfo *pi, ps; + struct dpkg_ar *part; + + 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..177d52b --- /dev/null +++ b/src/split/join.c @@ -0,0 +1,152 @@ +/* + * 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; + 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]; + int fd_in; + + 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..0a7ba8b --- /dev/null +++ b/src/split/queue.c @@ -0,0 +1,374 @@ +/* + * 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; + struct stat stab; + off_t bytes; + bool part_found; + + if (*argv) + badusage(_("--%s takes no arguments"), cipaction->olong); + + queue = scandepot(); + + part_found = false; + for (pq= queue; pq; pq= pq->nextinqueue) { + if (pq->info.md5sum) continue; + if (!part_found) { + printf(_("Junk files left around in the depot directory:\n")); + part_found = true; + } + 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 (part_found) + putchar('\n'); + + part_found = false; + for (pq= queue; pq; pq= pq->nextinqueue) { + struct partinfo ti; + int i; + + if (!pq->info.md5sum) continue; + mustgetpartinfo(pq->info.filename,&ti); + if (!part_found) { + printf(_("Packages not yet reassembled:\n")); + part_found = false; + } + + 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) +{ + struct partqueue *queue; + + queue = scandepot(); + if (*argv) { + const char *thisarg; + struct partqueue *pq; + + 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..771de62 --- /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" DEBEXT, + prefixdir, prefix_max, prefix, refname); + free(refname); + } else { + varbuf_printf(&file_dst, "%s.%dof%d" DEBEXT, + 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..07c8757 --- /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, FHFF_NONE); + + return &file->statoverride; +} + +static int +statdb_node_remove(const char *filename) +{ + struct fsys_namenode *file; + + file = fsys_hash_find_node(filename, FHFF_NO_NEW); + 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..2bba56d --- /dev/null +++ b/src/trigger/main.c @@ -0,0 +1,271 @@ +/* + * 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 opt_noact; +static int opt_await = 1; +static const char *opt_bypackage; + +static const char *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 (!opt_await) + opt_bypackage = "-"; + + if (opt_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(opt_bypackage, "-") == 0) { + pkg = NULL; + } else { + pkg = pkg_spec_parse_pkg(opt_bypackage, &err); + } + + /* Normalize the bypackage name if there was no error. */ + if (pkg) + opt_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(opt_bypackage); + done_trig = true; +} + +static void +tdm_add_package(const char *awname) +{ + if (ctrig && strcmp(awname, opt_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"), + opt_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 (!opt_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, opt_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, &opt_bypackage }, + { "await", 0, 0, &opt_await, NULL, NULL, 1 }, + { "no-await", 0, 0, &opt_await, NULL, NULL, 0 }, + { "no-act", 0, 0, &opt_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; +} |