#!/bin/sh # linaro-hwpack-install - Install a Linaro Hardware Pack. # This script is meant to run inside a chroot. It must not depend on anything # that's not in there. # TODO: When upgrading to a newer hwpack, make sure packages and apt sources # that are no longer needed are removed. # Copyright (C) 2010, 2011 Linaro # # Author: Guilherme Salgado # # This file is part of Linaro Image Tools. # # Linaro Image Tools 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. # # Linaro Image Tools 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 Linaro Image Tools; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. set -e if [ -n "${TMPDIR+x}" ]; then echo -e "\nWARNING: TMPDIR variable is set. It will be unset because in chroot environment it likely doesn't exist and can lead to error messages.\n" unset TMPDIR fi LOCKFILE="/var/lock/hwpack" TEMP_DIR=$(mktemp -d) HWPACK_DIR="${TEMP_DIR}/unpacked" INSTALL_LATEST="no" FORCE_YES="no" SOURCES_LIST_FILE="${TEMP_DIR}/sources.list" APT_GET_OPTIONS="Dir::Etc::SourceList=${SOURCES_LIST_FILE}" SUPPORTED_FORMATS="1.0 2.0 3.0" # A space-separated list of hwpack formats. FLASH_KERNEL_SKIP="true" export FLASH_KERNEL_SKIP # skip attempting to run flash-kernel-hooks DISTRIBUTION=`grep '^ID=' /etc/os-release | sed 's/ID=//'` sudo="sudo" if [ $(id -u) -eq 0 ]; then sudo="" fi die() { echo -e "$@" exit 1 } usage_msg="Usage: $(basename $0) [--install-latest] [--force-yes] [--extract-kernel-only] --hwpack-version --hwpack-arch --hwpack-name HWPACK_TARBALL" if [ $# -eq 0 ]; then die $usage_msg fi HWPACK_TARBALL_FOUND="no" HWPACK_VERSION="" HWPACK_ARCH="" HWPACK_NAME="" EXTRACT_KERNEL_ONLY="no" while [ $# -gt 0 ]; do case "$1" in --install-latest) INSTALL_LATEST="yes" shift;; --force-yes) FORCE_YES="yes" shift;; --hwpack-version) HWPACK_VERSION=$2 shift; shift;; --hwpack-arch) HWPACK_ARCH=$2 shift; shift;; --hwpack-name) HWPACK_NAME=$2 shift; shift;; --extract-kernel-only) EXTRACT_KERNEL_ONLY="yes" shift;; --*) die $usage_msg "\nUnrecognized option: \"$1\"";; *) [ "$HWPACK_TARBALL_FOUND" = "yes" ] && die $usage_msg HWPACK_TARBALL="$1" HWPACK_TARBALL_FOUND="yes" shift;; esac done [ "$HWPACK_TARBALL_FOUND" = "no" ] && die $usage_msg [ "$HWPACK_VERSION" = "" ] && die $usage_msg [ "$HWPACK_ARCH" = "" ] && die $usage_msg [ "$HWPACK_NAME" = "" ] && die $usage_msg setup_hwpack() { # This creates all the directories we need. mkdir -p "$HWPACK_DIR" # Unpack the hwpack tarball. We don't download it here because the chroot may # not contain any tools that would allow us to do that. echo -n "Unpacking hardware pack ..." tar zxf "$HWPACK_TARBALL" -C "$HWPACK_DIR" echo "Done" # Check the format of the hwpack is supported. hwpack_format=$(cat ${HWPACK_DIR}/FORMAT) supported="false" for format in $SUPPORTED_FORMATS; do if [ "x$hwpack_format" = "x$format" ]; then supported="true" break fi done [ $supported = "true" ] || \ die "Unsupported hwpack format: $hwpack_format. "\ "Try using a newer version of $(basename $0)." # Check the architecture of the hwpack matches that of the host system. if [ "x$EXTRACT_KERNEL_ONLY" = "xno" ]; then # TODO: create a generic way to identify the architecture, without depending on dpkg [ "$HWPACK_ARCH" = `dpkg --print-architecture` ] || \ die "Hardware pack architecture ($HWPACK_ARCH) does not match the host's architecture" fi } setup_apt_sources() { # Install the apt sources that contain the packages we need. for filename in $(ls "${HWPACK_DIR}"/sources.list.d/); do file="${HWPACK_DIR}"/sources.list.d/$filename should_install=0 stripped_file=${TEMP_DIR}/$filename grep -v "\(^#\|^\s*$\)" $file > $stripped_file while read line; do # Only install files that have at least one line not present in the # existing sources lists. grep -qF "$line" $(find /etc/apt/sources.list.d/ -name '*.list') /etc/apt/sources.list \ || should_install=1 done < $stripped_file if [ $should_install -eq 1 ]; then $sudo cp $file /etc/apt/sources.list.d/hwpack.$filename fi done # Import the OpenPGP keys for the files installed above. for filename in $(ls "${HWPACK_DIR}"/sources.list.d.gpg/); do file="${HWPACK_DIR}"/sources.list.d.gpg/$filename $sudo apt-key add $file done # Add one extra apt source for the packages included in the hwpack and make # sure it's the first on the list of sources so that it gets precedence over # the others. echo "deb file:${HWPACK_DIR}/pkgs ./" > "$SOURCES_LIST_FILE" cat /etc/apt/sources.list >> "$SOURCES_LIST_FILE" if [ "$FORCE_YES" = "yes" ]; then FORCE_OPTIONS="--yes --force-yes" else FORCE_OPTIONS="" fi # Do two updates. The first doesn't try to download package lists: # * First update doesn't access net # - not allowed to fail. Image file + hwpack should contain all packages # needed to create image. If this update fails we have problems. # * Second update may fail # - If can't download package updates (the only difference between the two # commands), we should still be OK. echo "Updating apt package lists ..." $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" update -q --no-download --ignore-missing $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" update -q || true } setup_ubuntu_rootfs() { # Prevent daemons to start in the chroot echo "exit 101" > /usr/sbin/policy-rc.d chmod a+x /usr/sbin/policy-rc.d mv -f /sbin/start-stop-daemon /sbin/start-stop-daemon.REAL cat > /sbin/start-stop-daemon << EOF #!/bin/sh echo "Warning: Fake start-stop-daemon called, doing nothing" EOF chmod 755 /sbin/start-stop-daemon if [ -x /sbin/initctl ]; then mv -f /sbin/initctl /sbin/initctl.REAL cat > /sbin/initctl << EOF #!/bin/sh echo "Warning: Fake initctl called, doing nothing" EOF chmod 755 /sbin/initctl fi # Create dummy fstab. fsck initramfs-tools hook is reading fstab entries # in order to copy e2fsck into initramfs image [ -f /etc/fstab ] && mv -f /etc/fstab /etc/fstab.REAL echo "UUID=00000000-0000-0000-0000-000000000000 / ext4 defaults 0 1" > /etc/fstab } install_deb_packages() { echo -n "Installing packages ..." # "newer" hwpacks contain a dependency package whose Depends is the # same as the packages config setting from the file the hwpack was # build from. But if we just installed that, a newer version of a # package than that in the hwpack might have made it to the main # archive and apt-get would install that instead. So we install the # specific package versions that make up the hwpack. /That/ however # would leave all the packages from the hwpack marked as manually # installed, so if a newer hwpack was installed over the top which no # longer depended on one of the packages the older one did, the # package would not be eligible for autoremoval. So we mark the all # packages newly installed as part of hwpack installed (apart from the # dependency package) as automatically installed with apt-get # markauto. # # For "older" hwpacks that don't have a dependency package, we just # manually install the contents of the hwpack. dependency_package="hwpack-${HWPACK_NAME}" if grep -q "^${dependency_package}=${HWPACK_VERSION}\$" "${HWPACK_DIR}"/manifest; then DEP_PACKAGE_PRESENT="yes" else DEP_PACKAGE_PRESENT="no" fi packages_without_versions=`sed 's/=.*//' "${HWPACK_DIR}"/manifest` packages_with_versions=`cat "${HWPACK_DIR}"/manifest` if [ "$INSTALL_LATEST" = "yes" ]; then packages="${packages_without_versions}" else packages="${packages_with_versions}" fi if [ "$DEP_PACKAGE_PRESENT" = "yes" ]; then to_be_installed= for package in $packages_without_versions; do if [ "${package}" != "${dependency_package}" ]; then { dpkg --get-selections $package 2>/dev/null| grep -qw 'install$'; } || to_be_installed="$to_be_installed $package" fi done fi $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" install ${packages} if [ "$DEP_PACKAGE_PRESENT" = "yes" ]; then if [ -n "${to_be_installed}" ]; then $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" markauto ${to_be_installed} fi fi } extract_kernel_packages() { echo "Extracting all kernel packages ..." # We assume the hwpack is always available at the rootfs ROOTFS_DIR=$(dirname $HWPACK_TARBALL) ls ${HWPACK_DIR}/pkgs/linux-[ih]*.deb | while read pkg; do echo "Extracting package `basename $pkg`" dpkg-deb -x ${pkg} $ROOTFS_DIR done ls ${HWPACK_DIR}/pkgs/*-pre-boot*.deb | while read pkg; do echo "Extracting package `basename $pkg`" dpkg-deb -x ${pkg} $ROOTFS_DIR done ls ${HWPACK_DIR}/pkgs/uefi-image-*.deb | while read pkg; do echo "Extracting package `basename $pkg`" dpkg-deb -x ${pkg} $ROOTFS_DIR done # manually generate modules.dep ls $ROOTFS_DIR/lib/modules | while read kernel; do depmod -b $ROOTFS_DIR ${kernel} || true done; } cleanup() { # Ensure our temp dir and apt sources are removed. echo -n "Cleaning up ..." rm -rf $TEMP_DIR if [ "x$EXTRACT_KERNEL_ONLY" = "xno" ]; then rm -f /usr/sbin/policy-rc.d mv -f /sbin/start-stop-daemon.REAL /sbin/start-stop-daemon if [ -x /sbin/initctl.REAL ]; then mv -f /sbin/initctl.REAL /sbin/initctl fi rm -f /etc/fstab [ -f /etc/fstab.REAL ] && mv -f /etc/fstab.REAL /etc/fstab # Do two updates. The first doesn't try to download package lists: # * First update doesn't access net # - not allowed to fail. Image file + hwpack should contain all packages # needed to create image. If this update fails we have problems. # * Second update may fail # - If can't download package updates (the only difference between the two # commands), we should still be OK. $sudo apt-get update -qq --no-download --ignore-missing $sudo apt-get update -qq || true fi echo "Done" } ## main # Try to acquire fd #9 (i.e. /var/lock/hwpack) # Using 9 as the file descriptor because of https://launchpad.net/bugs/249620 exec 9>$LOCKFILE flock -n 9 || die "Could not acquire lock: $LOCKFILE" # From now on we'll be making changes to the system, so we need to clean # things up when the script exits. trap cleanup EXIT # Extract and set up the hwpack at the rootfs setup_hwpack # In case we only care about the kernel, don't mess up with the system if [ "x$EXTRACT_KERNEL_ONLY" = "xno" ]; then setup_apt_sources setup_ubuntu_rootfs install_deb_packages else extract_kernel_packages fi echo "Done"