diff --git a/dpkg_no_scripts.sh b/dpkg_no_scripts.sh index 90dc377adc..c2cc7c345e 100755 --- a/dpkg_no_scripts.sh +++ b/dpkg_no_scripts.sh @@ -22,6 +22,8 @@ # Flags DEFINE_string root "" \ "The target rootfs directory in which to install packages." +DEFINE_boolean dpkg_fallback $FLAGS_TRUE \ + "Run normal dpkg if maintainer scripts are not whitelisted." DEFINE_string status_fd "" \ "The file descriptor to report status on; ignored." DEFINE_boolean unpack $FLAGS_FALSE "Is the action 'unpack'?" @@ -43,52 +45,144 @@ eval set -- "${FLAGS_ARGV}" # Die on any errors. set -e -if [ $FLAGS_configure -eq $FLAGS_TRUE ]; then - # We ignore configure requests. - exit 0 -fi -if [ $FLAGS_remove -eq $FLAGS_TRUE ]; then - # We log but ignore remove requests. - echo "dpkg_no_scripts, remove: $@" - exit 0 -fi -if [ $FLAGS_unpack -ne $FLAGS_TRUE ]; then - # Ignore unknown command line. - echo "Unexpected command line: $@" - exit 0 -fi -if [ -z "$FLAGS_root" ]; then - echo "Missing root directory." - exit 0 -fi +# Returns true if the input file is whitelisted. +# +# $1 - The file to check +is_whitelisted() { + local whitelist="${SRC_ROOT}/package_scripts/package.whitelist" + test -f "$whitelist" || return -DPKG_STATUS="" -if [ -d "$FLAGS_root/var/lib/dpkg" ]; then - DPKG_STATUS="$FLAGS_root/var/lib/dpkg/status" - DPKG_INFO="$FLAGS_root/var/lib/dpkg/info/" -fi + local checksum=$(md5sum "$1" | awk '{ print $1 }') + local count=$(grep -c "$checksum" "${whitelist}" || /bin/true) + test $count -ne 0 +} -for p in "$@"; do - echo "Extracting $p" - dpkg-deb --extract "$p" "$FLAGS_root" +# Returns true if either of the two given files exist and are not whitelisted. +# +# $1 - The package name. +# $2 - The path to the preinst file if it were to exist. +# $3 - The path to the postinst file if it were to exist. +has_missing_whitelist() { + local package=$1 + local preinst=$2 + local postinst=$3 + local missing_whitelist=0 - if [ -n "$DPKG_STATUS" ]; then - TMPDIR=$(mktemp -d) - dpkg-deb --control "$p" "$TMPDIR" + if [ -f "$preinst" ]; then + if ! is_whitelisted "$preinst"; then + missing_whitelist=1 + echo "Warning: Missing whitelist entry for ${package}.preinst" + fi + fi + if [ -f "$postinst" ]; then + if ! is_whitelisted "$postinst"; then + missing_whitelist=1 + echo "Warning: Missing whitelist entry for ${package}.postinst" + fi + fi + test $missing_whitelist -ne 0 +} + +do_configure() { + local dpkg_info="$FLAGS_root/var/lib/dpkg/info/" + local fallback_packages="" + + for p in "$@"; do + echo "Configuring: $p" + + # Make sure that any .preinst or .postinst files are whitelisted. + local preinst="${dpkg_info}/${p}.preinst" + local postinst="${dpkg_info}/${p}.postinst" + if has_missing_whitelist "$p" "$preinst" "$postinst"; then + if [ $FLAGS_dpkg_fallback -eq $FLAGS_TRUE ]; then + echo "** Warning: Will run full maintainer scripts for ${p}." + fallback_packages="$fallback_packages $p" + continue + else + # TODO: Eventually should be upgraded to a full error. + echo "** Warning: Ignoring missing whitelist for ${p}." + fi + fi + + # Run our maintainer script for this package if we have one. + local chromium_postinst="${SRC_ROOT}/package_scripts/${p}.postinst" + if [ -f "$chromium_postinst" ]; then + echo "Running: $chromium_postinst" + ROOT="$FLAGS_root" SRC_ROOT="$SRC_ROOT" sh -x $chromium_postinst + fi + done + + if [ -n "$fallback_packages" ]; then + dpkg --root="$FLAGS_root" --configure $fallback_packages + fi +} + +do_unpack() { + local dpkg_status="$FLAGS_root/var/lib/dpkg/status" + local dpkg_info="$FLAGS_root/var/lib/dpkg/info/" + + for p in "$@"; do + local package=$(dpkg-deb --field "$p" Package) + local tmpdir=$(mktemp -d) + + dpkg-deb --control "$p" "$tmpdir" + + local preinst="${tmpdir}/preinst" + local postinst="${tmpdir}/postinst" + if has_missing_whitelist "$package" "$preinst" "$postinst"; then + if [ $FLAGS_dpkg_fallback -eq $FLAGS_TRUE ]; then + echo "** Warning: Running full maintainer scripts for ${package}." + dpkg --root="$FLAGS_root" --unpack --auto-deconfigure "$p" + rm -rf "$tmpdir" + continue + else + # TODO: Eventually should be upgraded to a full error. + echo "** Warning: Ignoring missing whitelist for ${p}." + fi + fi # Copy the info files - PACKAGE=$(dpkg-deb --field "$p" Package) - FILES=$(ls "$TMPDIR" | grep -v control) - for f in $FILES; do - cp "${TMPDIR}/$f" "${DPKG_INFO}/$PACKAGE.$f" + local files=$(ls "$tmpdir" | grep -v control) + for f in $files; do + cp "${tmpdir}/${f}" "${dpkg_info}/${package}.${f}" done - touch "${DPKG_INFO}/$PACKAGE.list" + touch "${dpkg_info}/${package}.list" # TODO: Proper .list files. # Mark the package as installed successfully. - echo "Status: install ok installed" >> "$DPKG_STATUS" - cat "${TMPDIR}/control" >> "$DPKG_STATUS" - echo "" >> "$DPKG_STATUS" + echo "Status: install ok installed" >> "$dpkg_status" + cat "${tmpdir}/control" >> "$dpkg_status" + echo "" >> "$dpkg_status" - rm -rf "$TMPDIR" - fi -done + rm -rf "$tmpdir" + + # Run our maintainer script for this package if we have one. + local chromium_postinst="${SRC_ROOT}/package_scripts/${package}.preinst" + if [ -f "$chromium_preinst" ]; then + echo "Running: ${chromium_preinst}" + ROOT="$FLAGS_root" SRC_ROOT="$SRC_ROOT" $chromium_preinst + fi + + echo "Unpacking: $p" + dpkg-deb --extract "$p" "$FLAGS_root" + done +} + +# This script requires at least "--root=" +if [ -z "$FLAGS_root" ]; then + echo "dpkg_no_scripts: Missing root directory." + exit 1 +fi + +if [ $FLAGS_configure -eq $FLAGS_TRUE ]; then + do_configure $@ +elif [ $FLAGS_unpack -eq $FLAGS_TRUE ]; then + do_unpack $@ +elif [ $FLAGS_remove -eq $FLAGS_TRUE ]; then + # We log but ignore remove requests. + echo "Ignoring remove: $@" +else + echo "dpkg_no_scripts.sh: Unknown or missing command." + exit 1 +fi + +exit 0 diff --git a/install_packages.sh b/install_packages.sh index 341a1f2a9c..b9c9d957d2 100755 --- a/install_packages.sh +++ b/install_packages.sh @@ -101,10 +101,6 @@ APT_CACHE_DIR="${FLAGS_build_root}/apt_cache-${FLAGS_target}/" mkdir -p "${APT_CACHE_DIR}/archives/partial" # Create the apt configuration file. See "man apt.conf" -NO_MAINTAINER_SCRIPTS="" -if [ -n "$EXPERIMENTAL_NO_MAINTAINER_SCRIPTS" ]; then - NO_MAINTAINER_SCRIPTS="Bin { dpkg \"${SCRIPTS_DIR}/dpkg_no_scripts.sh\"; };" -fi APT_PARTS="${OUTPUT_DIR}/apt.conf.d" mkdir -p "$APT_PARTS" # An empty apt.conf.d to avoid other configs. export APT_CONFIG="${OUTPUT_DIR}/apt.conf" @@ -121,7 +117,9 @@ APT }; Dir { - $NO_MAINTAINER_SCRIPTS + Bin { + dpkg "${SCRIPTS_DIR}/dpkg_no_scripts.sh"; + }; Cache "$APT_CACHE_DIR"; Cache { archives "${APT_CACHE_DIR}/archives"; @@ -185,59 +183,24 @@ for p in $PACKAGES $EXTRA_PACKAGES; do PKG=$(ls "${REPO}"/${p}_*_all.deb) fi sudo "${SCRIPTS_DIR}"/dpkg_no_scripts.sh \ - --root="$ROOT_FS_DIR" --unpack "$PKG" + --root="$ROOT_FS_DIR" --nodpkg_fallback --unpack "$PKG" + sudo "${SCRIPTS_DIR}"/dpkg_no_scripts.sh \ + --root="$ROOT_FS_DIR" --nodpkg_fallback --configure "$p" done # Make sure that apt is ready to work. We use --fix-broken to trigger apt # to install additional critical packages. If there are any of these, we # disable the maintainer scripts so they install ok. -TMP_FORCE_NO_SCRIPTS="-o=Dir::Bin::dpkg=${SCRIPTS_DIR}/dpkg_no_scripts.sh" +TMP_FORCE_NO_SCRIPTS="-o=DPkg::options::=--nodpkg_fallback" sudo APT_CONFIG="$APT_CONFIG" DEBIAN_FRONTEND=noninteractive \ apt-get $TMP_FORCE_NO_SCRIPTS --force-yes --fix-broken install -# ----- MAINTAINER SCRIPT FIXUPS ----- - -# TODO: Remove when we stop having maintainer scripts altogether. +# TODO: Remove these hacks when we stop having maintainer scripts altogether. sudo cp -a /dev/* "${ROOT_FS_DIR}/dev" sudo cp -a /etc/resolv.conf "${ROOT_FS_DIR}/etc/resolv.conf" sudo ln -sf /bin/true "${ROOT_FS_DIR}/usr/sbin/invoke-rc.d" sudo ln -sf /bin/true "${ROOT_FS_DIR}/usr/sbin/update-rc.d" -# base-files -# TODO: Careful audit of the postinst; this isn't all that is there. -sudo cp -a "${ROOT_FS_DIR}/usr/share/base-files/networks" \ - "${ROOT_FS_DIR}/usr/share/base-files/nsswitch.conf" \ - "${ROOT_FS_DIR}/usr/share/base-files/profile" \ - "${ROOT_FS_DIR}/etc/" - -# base-passwd -sudo cp "${ROOT_FS_DIR}/usr/share/base-passwd/passwd.master" \ - "${ROOT_FS_DIR}/etc/passwd" -sudo cp "${ROOT_FS_DIR}/usr/share/base-passwd/group.master" \ - "${ROOT_FS_DIR}/etc/group" - -# libpam-runtime -# The postinst script calls pam-auth-update, which is a perl script that -# expects to run within the targetfs. Until we fix this, we just copy -# from the build chroot. -sudo cp -a /etc/pam.d/common-* \ - /etc/pam.d/login \ - /etc/pam.d/newusers \ - /etc/pam.d/su \ - /etc/pam.d/sudo \ - "${ROOT_FS_DIR}/etc/pam.d/" - -# mawk -sudo ln -s mawk "${ROOT_FS_DIR}/usr/bin/awk" - -# base-files? -sudo touch "${ROOT_FS_DIR}/etc/fstab" - -# sysv-rc needs this -sudo mkdir -p "${ROOT_FS_DIR}/etc/init.d" - -# ----- END MAINTAINER SCRIPT FIXUPS ----- - # Set up mounts for working within the rootfs. We copy some basic # network information from the host so that maintainer scripts can # access the network as needed.