Always use our dpkg wrapper when mastering an image.

This changes install_packages to always have apt use our dpkg
wrapper when building an image. The dpkg_no_scripts.sh has been
modified to check if a package's maintainer scripts have been
whitelisted. If so, it will install without maintainer scripts.
If any relevant maintainer script has not been whitelisted it
will fall back to standard dpkg which will process the
maintainer scripts.

This will allow us to transition to installing packages without
maintainer scripts in batches rather than all at once. Once
everything is switched over we will have dpkg_no_scripts.sh
throw an error if it encounters a package with maintainer
scripts that have not been whitelisted.

Move postinst stuff from install_packages.sh to actual postinst
scripts.

Review URL: http://codereview.chromium.org/549017
This commit is contained in:
tedbo 2010-01-11 17:34:44 -08:00
parent 55d1c59a58
commit 3d9b18913c
2 changed files with 142 additions and 85 deletions

View File

@ -22,6 +22,8 @@
# Flags # Flags
DEFINE_string root "" \ DEFINE_string root "" \
"The target rootfs directory in which to install packages." "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 "" \ DEFINE_string status_fd "" \
"The file descriptor to report status on; ignored." "The file descriptor to report status on; ignored."
DEFINE_boolean unpack $FLAGS_FALSE "Is the action 'unpack'?" DEFINE_boolean unpack $FLAGS_FALSE "Is the action 'unpack'?"
@ -43,52 +45,144 @@ eval set -- "${FLAGS_ARGV}"
# Die on any errors. # Die on any errors.
set -e set -e
if [ $FLAGS_configure -eq $FLAGS_TRUE ]; then # Returns true if the input file is whitelisted.
# We ignore configure requests. #
exit 0 # $1 - The file to check
fi is_whitelisted() {
if [ $FLAGS_remove -eq $FLAGS_TRUE ]; then local whitelist="${SRC_ROOT}/package_scripts/package.whitelist"
# We log but ignore remove requests. test -f "$whitelist" || return
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
DPKG_STATUS="" local checksum=$(md5sum "$1" | awk '{ print $1 }')
if [ -d "$FLAGS_root/var/lib/dpkg" ]; then local count=$(grep -c "$checksum" "${whitelist}" || /bin/true)
DPKG_STATUS="$FLAGS_root/var/lib/dpkg/status" test $count -ne 0
DPKG_INFO="$FLAGS_root/var/lib/dpkg/info/" }
fi
for p in "$@"; do # Returns true if either of the two given files exist and are not whitelisted.
echo "Extracting $p" #
dpkg-deb --extract "$p" "$FLAGS_root" # $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 if [ -f "$preinst" ]; then
TMPDIR=$(mktemp -d) if ! is_whitelisted "$preinst"; then
dpkg-deb --control "$p" "$TMPDIR" 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 # Copy the info files
PACKAGE=$(dpkg-deb --field "$p" Package) local files=$(ls "$tmpdir" | grep -v control)
FILES=$(ls "$TMPDIR" | grep -v control) for f in $files; do
for f in $FILES; do cp "${tmpdir}/${f}" "${dpkg_info}/${package}.${f}"
cp "${TMPDIR}/$f" "${DPKG_INFO}/$PACKAGE.$f"
done done
touch "${DPKG_INFO}/$PACKAGE.list" touch "${dpkg_info}/${package}.list" # TODO: Proper .list files.
# Mark the package as installed successfully. # Mark the package as installed successfully.
echo "Status: install ok installed" >> "$DPKG_STATUS" echo "Status: install ok installed" >> "$dpkg_status"
cat "${TMPDIR}/control" >> "$DPKG_STATUS" cat "${tmpdir}/control" >> "$dpkg_status"
echo "" >> "$DPKG_STATUS" echo "" >> "$dpkg_status"
rm -rf "$TMPDIR" 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 fi
done
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

View File

@ -101,10 +101,6 @@ APT_CACHE_DIR="${FLAGS_build_root}/apt_cache-${FLAGS_target}/"
mkdir -p "${APT_CACHE_DIR}/archives/partial" mkdir -p "${APT_CACHE_DIR}/archives/partial"
# Create the apt configuration file. See "man apt.conf" # 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" APT_PARTS="${OUTPUT_DIR}/apt.conf.d"
mkdir -p "$APT_PARTS" # An empty apt.conf.d to avoid other configs. mkdir -p "$APT_PARTS" # An empty apt.conf.d to avoid other configs.
export APT_CONFIG="${OUTPUT_DIR}/apt.conf" export APT_CONFIG="${OUTPUT_DIR}/apt.conf"
@ -121,7 +117,9 @@ APT
}; };
Dir Dir
{ {
$NO_MAINTAINER_SCRIPTS Bin {
dpkg "${SCRIPTS_DIR}/dpkg_no_scripts.sh";
};
Cache "$APT_CACHE_DIR"; Cache "$APT_CACHE_DIR";
Cache { Cache {
archives "${APT_CACHE_DIR}/archives"; archives "${APT_CACHE_DIR}/archives";
@ -185,59 +183,24 @@ for p in $PACKAGES $EXTRA_PACKAGES; do
PKG=$(ls "${REPO}"/${p}_*_all.deb) PKG=$(ls "${REPO}"/${p}_*_all.deb)
fi fi
sudo "${SCRIPTS_DIR}"/dpkg_no_scripts.sh \ 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 done
# Make sure that apt is ready to work. We use --fix-broken to trigger apt # 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 # to install additional critical packages. If there are any of these, we
# disable the maintainer scripts so they install ok. # 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 \ sudo APT_CONFIG="$APT_CONFIG" DEBIAN_FRONTEND=noninteractive \
apt-get $TMP_FORCE_NO_SCRIPTS --force-yes --fix-broken install apt-get $TMP_FORCE_NO_SCRIPTS --force-yes --fix-broken install
# ----- MAINTAINER SCRIPT FIXUPS ----- # TODO: Remove these hacks when we stop having maintainer scripts altogether.
# TODO: Remove when we stop having maintainer scripts altogether.
sudo cp -a /dev/* "${ROOT_FS_DIR}/dev" sudo cp -a /dev/* "${ROOT_FS_DIR}/dev"
sudo cp -a /etc/resolv.conf "${ROOT_FS_DIR}/etc/resolv.conf" 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/invoke-rc.d"
sudo ln -sf /bin/true "${ROOT_FS_DIR}/usr/sbin/update-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 # Set up mounts for working within the rootfs. We copy some basic
# network information from the host so that maintainer scripts can # network information from the host so that maintainer scripts can
# access the network as needed. # access the network as needed.