#!/bin/sh set -e TESTDIR=$(readlink -f $(dirname $0)) . $TESTDIR/framework setupenvironment configarchitecture 'native' # create a bunch of failures createfailure() { setupsimplenativepackage "failure-$1" 'native' '1.0' 'unstable' 'Depends: dependee' BUILDDIR="incoming/failure-$1-1.0" echo '#!/bin/sh exit 29' > ${BUILDDIR}/debian/$1 buildpackage "$BUILDDIR" 'unstable' 'main' 'native' rm -rf "$BUILDDIR" } buildsimplenativepackage 'dependee' 'native' '1.0' 'unstable' createfailure 'preinst' createfailure 'postinst' createfailure 'prerm' createfailure 'postrm' setupaptarchive # create a library to noop chroot() and rewrite maintainer script executions # via execvp() as used by dpkg as we don't want our rootdir to be a fullblown # chroot directory dpkg could chroot into to execute the maintainer scripts cat << EOF > noopchroot.c #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> static char * chrootdir = NULL; int chroot(const char *path) { printf("WARNING: CHROOTing to %s was ignored!\n", path); free(chrootdir); chrootdir = strdup(path); return 0; } int execvp(const char *file, char *const argv[]) { static int (*func_execvp) (const char *, char * const []) = NULL; if (func_execvp == NULL) func_execvp = (int (*) (const char *, char * const [])) dlsym(RTLD_NEXT, "execvp"); if (chrootdir == NULL || strncmp(file, "/var/lib/dpkg/", strlen("/var/lib/dpkg/")) != 0) return func_execvp(file, argv); printf("REWRITE execvp call %s into %s\n", file, chrootdir); char newfile[strlen(chrootdir) + strlen(file)]; strcpy(newfile, chrootdir); strcat(newfile, file); return func_execvp(newfile, argv); } EOF testsuccess gcc -fPIC -shared -o noopchroot.so noopchroot.c -ldl mkdir -p "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/" DPKG="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" echo "#!/bin/sh if [ -n \"\$LD_PRELOAD\" ]; then export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so \${LD_PRELOAD}\" else export LD_PRELOAD=\"${TMPWORKINGDIRECTORY}/noopchroot.so\" fi dpkg \"\$@\"" > $DPKG chmod +x $DPKG sed -ie "s|^DPKG::options:: \"dpkg\";\$|DPKG::options:: \"$DPKG\";|" aptconfig.conf # setup some pre- and post- invokes to check the output isn't garbled later APTHOOK="${TMPWORKINGDIRECTORY}/rootdir/usr/bin/apthook" echo '#!/bin/sh echo "$1: START" echo "$1: MaiN" echo "$1: ENd"' > $APTHOOK chmod +x $APTHOOK echo "DPKG::Pre-Invoke:: \"${APTHOOK} PRE\"; DPKG::Post-Invoke:: \"${APTHOOK} POST\";" > rootdir/etc/apt/apt.conf.d/99apthooks testmyfailure() { local PROGRESS='rootdir/tmp/progress.log' exec 3> $PROGRESS testfailure "$@" -o APT::Status-Fd=3 msgtest 'Test for failure message of maintainerscript in' 'console log' local TEST='rootdir/tmp/testfailure.output' if grep -q 'exit status 29$' "$TEST"; then msgpass else cat $TEST msgfail fi msgtest 'Test for proper execution of invoke scripts in' 'console log' if grep -q '^PRE: START$' $TEST && grep -q '^PRE: MaiN$' $TEST && grep -q '^PRE: ENd$' $TEST && grep -q '^POST: START$' $TEST && grep -q '^POST: MaiN$' $TEST && grep -q '^POST: ENd$' $TEST; then msgpass else cat $TEST msgfail fi msgtest 'Test for failure message of maintainerscript in' 'progress log' if grep -q '^pmerror:.\+exit status 29$' "$PROGRESS"; then msgpass else cat $PROGRESS msgfail fi testmarkedauto 'dependee' } cp -a rootdir/var/lib/dpkg/status rootdir/var/lib/dpkg/status.backup testmyfailure aptget install failure-preinst -y cp -a rootdir/var/lib/dpkg/status.backup rootdir/var/lib/dpkg/status testmyfailure aptget install failure-postinst -y cp -a rootdir/var/lib/dpkg/status.backup rootdir/var/lib/dpkg/status testsuccess aptget install failure-prerm -y testdpkginstalled failure-prerm testmyfailure aptget purge failure-prerm -y cp -a rootdir/var/lib/dpkg/status.backup rootdir/var/lib/dpkg/status testsuccess aptget install failure-postrm -y testdpkginstalled failure-postrm testmyfailure aptget purge failure-postrm -y # FIXME: test with output going to a PTY as it usually does #cp -a rootdir/var/lib/dpkg/status.backup rootdir/var/lib/dpkg/status #aptget install failure-preinst -y