PKGBUILDs/util/archmobile
2009-09-26 09:35:50 -05:00

430 lines
12 KiB
Bash
Executable file

#! /bin/bash
# Default values.
DEFAULT_MIRROR='http://hiciu.rootnode.net/arch-arm'
# Command line options and default values.
DEBUG='n'
SUDO='y'
HELP='n'
BUILD='n'
CHROOT='n'
# ARCH can be specified on the command line. Otherwise we'll guess.
ARCH='i686'
# Which groups and additional packages are to install.
TARGETS=()
# PACMAN_EXTRA takes extra flags passed to pacman. No checking is done.
PACMAN_EXTRA=''
# Default values of command line arguments.
DESTDIR=''
MIRROR=''
# Prints the help message, optionally using its first argument as script name.
printHelp() {
test -z "$1" && 1='archOnFr'
echo "$1 [-a arch] [-s] [-n] [-d] [-t TARGETS] DESTDIR [MIRROR]"
echo "$1 -b [-a arch] [-s] [-n] [-d] [-t TARGETS] DESTDIR [MIRROR]"
echo "$1 -e [-s] [-d] DIR"
echo "$1 -h"
echo
echo "In the first form $1 installs the base system suited to run on the smart phone"
echo "to DESTDIR optionally using a different mirror for the packages instead of the"
echo "default."
echo
echo "In the second form a build system is installed to DESTDIR optionally using a"
echo "different mirror. The build system is suited to run on the host pc to develop"
echo "Arch Mobile."
echo
echo "In the third form $1 enters the development environment given at DESTDIR."
echo
echo "In the fourth form this help message is printed."
echo
echo "OPTIONS"
echo " -a --arch=[i686|x86_64]"
echo " host system's architecture"
echo " -d --debug"
echo " print debug messages"
echo " -h --help"
echo " prints this help message"
echo " -p --extra=flags"
echo " add flags to pacman's flags when calling (use with care!)"
echo " -s --nosudo"
echo " don't use sudo for pacman calls (needs root previleges)"
echo " -t --targets=TARGETS"
echo " install TARGETS which might be groups or packages explicitly."
echo " (Default: base)"
echo
echo "EXAMPLES"
echo " $1 /media/card http://hiciu.rootnode.net/arch-arm"
echo " $1 /media/card file:///home/harlekin/archpkgs"
}
# Check if we are already able to interpret ARM binaries and configure the
# the kernel if we are not. Expects mount call and echo call as arguments.
binfmt_mount() {
MOUNT_CALL="$1"
ECHO_CALL="$2"
debug "Checking for binfmt_misc."
if [ ! -e /proc/sys/fs/binfmt_misc/register ]; then
debug "binfmt_misc not mounted."
debug "$MOUNT_CALL -t binfmt_misc none /proc/sys/fs/binfmt_misc"
$MOUNT_CALL -t binfmt_misc none /proc/sys/fs/binfmt_misc &>/dev/null
test $? -ne 0 && \
error "Failed to mount binfmt_misc."
fi
if [ ! -f /proc/sys/fs/binfmt_misc/arm ]; then
debug "$ECHO_CALL ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-static-arm:' > /proc/sys/fs/binfmt_misc/register"
$ECHO_CALL ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-static-arm:' > /proc/sys/fs/binfmt_misc/register
test $? -ne 0 && \
error "Failed to write ARM binary information to binfmt_misc/register."
debug "binfmt_misc successfully created and configured."
fi
}
debug() {
test "$DEBUG" = "y" && echo "debug: $1"
}
error() {
echo "error: $1"
doCleanup
exit 1
}
# Script for cleaning up all temporary files and reverting temporary changes
# (such as mounting) even if an error occurs. Takes an array as first argument
# which consists of the affected file, prefixed with the action.
# F:foo will remove the file foo
# D:bar will remove the directory bar recursively
# M:baz will un-mount bar
doCleanup() {
test ${#CLEANUP} -eq 0 && debug "Nothing to clean up."
debug "Cleaning up..."
for target in ${CLEANUP[*]}; do
action="${target:0:2}"
target="${target#?:}"
case "$action" in
F:)
debug "Removing file $target."
rm -f "$target"
;;
D:)
debug "Removing directory $target."
rm -rf "$target"
;;
M:)
debug "Unmounting $target."
if [ "$SUDO" = 'y' ]; then
sudo umount "$target"
else
umount "$target"
fi
;;
esac
done
}
# Print help if called without arguments and exit with error condition.
test $# -eq 0 && HELP='y!'
while [ $# -ne 0 ]; do
case "$1" in
--arch=*)
ARCH="${1#--arch=}"
;;
-a|--arch)
shift
ARCH="$1"
;;
-b|--build)
test $CHROOT = y && \
error "Command line option --build conflicts with --enter."
BUILD='y'
;;
-e|--enter)
test $BUILD = y && \
error "Command line option --enter conflicts with --build."
CHROOT='y'
;;
-h|--help)
HELP='y'
;;
--extra=)
PACMAN_EXTRA="${1#--extra=}"
;;
-p|--extra)
shift
PACMAN_EXTRA="$1"
;;
-d|--debug)
DEBUG='y'
;;
-s|--nosudo)
SUDO='n'
;;
--targets=)
TARGETS=(${TARGETS[*]} "${1#--targets=}")
;;
-t|--targets)
shift
TARGETS=(${TARGETS[*]} "$1")
;;
-*)
error "Unrecognized command line option $1."
exit 1
;;
*)
if [ -z "$DESTDIR" ]; then
DESTDIR="$1"
else
if [ -z "$MIRROR" ]; then
MIRROR="$1"
else
error "Unrecognized command line argument $1."
fi
fi
;;
esac; shift
done
# Print help message if requested or set because of invalied command line
# arguments.
if [ "$HELP" = 'y!' ]; then
printHelp "$(basename $0)"
exit 1
elif [ "$HELP" = 'y' ]; then
printHelp "$(basename $0)"
exit 0
fi
if [ -z "$ARCH" ]; then
debug "ARCH = ?"
else
debug "ARCH = $ARCH"
fi
debug "BUILD = $BUILD"
debug "FORCE = $FORCE"
debug "NODEPS = $NODEPS"
debug "SUDO = $SUDO"
debug "DESTDIR = $DESTDIR"
debug "CHROOT = $CHROOT"
if [ -z "${TARGETS[*]}" ]; then
debug "TARGETS = base"
else
debug "TARGETS = ${TARGETS[*]}"
fi
if [ -z "$MIRROR" ]; then
debug "MIRROR = $DEFAULT_MIRROR"
else
debug "MIRROR = $MIRROR"
fi
debug "PATH = $PATH"
debug "PACMAN_EXTRA = $PACMAN_EXTRA"
# Check for root privileges
test $SUDO = 'n' -a "$UID" -ne 0 && \
error "Need root privileges for pacman call or don't specify --nosudo."
# If we are using sudo we should check if it is installed.
debug "Checking for sudo."
if [ $SUDO = y ]; then
SUDO_CALL="$(which sudo 2>/dev/null)"
test $? -ne 0 && \
error "sudo couldn't be found on your system. Please install and configure it or use --nosudo and run as root."
fi
debug "sudo found as $SUDO_CALL."
# Set current working directory since we might change the directory
STARTDIR="$(pwd)"
test $? -ne 0 && error "Failed to obtain the current working directory."
# Check if DESTDIR is set
test -z "$DESTDIR" && error "DESTDIR not set."
# Prepare mount, echo and chroot calls.
MOUNT_CALL='mount'
ECHO_CALL='echo'
CHROOT_CALL='chroot'
test $SUDO = y && MOUNT_CALL="$SUDO_CALL $MOUNT_CALL"
test $SUDO = y && ECHO_CALL="$SUDO_CALL $ECHO_CALL"
test $SUDO = y && CHROOT_CALL="$SUDO_CALL $CHROOT_CALL"
# Entering buildsystem
if [ $CHROOT = y ]; then
debug "Entering build system."
binfmt_mount "$MOUNT_CALL" "$ECHO_CALL"
debug "$CHROOT_CALL $DESTDIR /bin/bash"
$CHROOT_CALL $DESTDIR /bin/bash
test $? -ne 0 && \
error "Failed to chroot into build systen in $DESTDIR."
exit 0
fi
# Set default mirror if MIRROR isn't set
test -z "$MIRROR" && MIRROR="$DEFAULT_MIRROR"
# If no targets are specified we default to the base group and the stock kernel.
test -z "${TARGETS[*]}" && TARGETS=(base kernel26)
# If we are installing the build environment we need to know the host system's
# architecture.
test -z "$ARCH" && ARCH="$(arch 2>/dev/null)"
test -z "$ARCH" && \
error "Could not obtain architecture type. Please use --arch manually."
if [ "$ARCH" != 'i686' -a "$ARCH" != 'x86_64' ]; then
error "Host system's architecture $ARCH is not supported"
fi
# Prepending the current working directory if DESTDIR isn't abolute. Safety
# measure as we're going to change to a temporary working directory.
if [ "${DESTDIR:0:1}" != "/" ]; then
debug 'DESTDIR not an absolute path. Prepending STARTDIR.'
DESTDIR="$STARTDIR/$DESTDIR"
fi
# Remove trailing / of MIRROR if necessary
MIRROR="${MIRROR%/}"
# Create DESTDIR if it doesn't exist yet.
if [ ! -d "$DESTDIR" ]; then
debug "Destination installation directory does not exist."
debug "Creating destination directory."
debug "mkdir -p \"$DESTDIR\" 2>/dev/null"
mkdir -p "$DESTDIR" 2>/dev/null
if [ $? -ne 0 ]; then
error "Failed to create $DESTDIR. Please create it manually and run again."
fi
fi
# Trying to find a pacman executable.
debug "Trying to find a pacman binary."
PACMAN="$(which pacman.static 2>/dev/null)"
if [ $? -ne 0 ]; then
debug "No pacman.static available in PATH."
PACMAN=''
fi
if [ -z "$PACMAN" ]; then
PACMAN="$(which pacman-static 2>/dev/null)"
if [ $? -ne 0 ]; then
debug "No pacman-static available in PATH."
PACMAN=''
fi
fi
if [ -z "$PACMAN" ]; then
PACMAN="$(which pacman 2>/dev/null)"
if [ $? -ne 0 ]; then
debug "No pacman available in PATH."
PACMAN=''
fi
fi
# Check if pacman is now available
test -z "$PACMAN" && \
error "Could not obtain pacman binary. Install pacman to your PATH and run again."
debug "Found pacman binary as $PACMAN."
# Creating temporary pacman.conf
debug "Creating temporary pacman.conf."
CONFIG="$(mktemp -t pacman.conf.XXXX 2>/dev/null)"
test $? -ne 0 && CONFIG=''
test -z "$CONFIG" && error "Failed to create temporary pacman.conf."
# Build up pacman's temporary configuration file. We need the build repository
# even when we're not perfoming a build environment installation because of the
# system dependent qemu.
CLEANUP=("F:$CONFIG" ${CLEANUP[*]})
echo "[build]" > "$CONFIG"
echo "Server = $MIRROR/$ARCH/build" >> "$CONFIG"
echo >> "$CONFIG"
echo "[core]" >> "$CONFIG"
echo "Server = $MIRROR/arm/core" >> "$CONFIG"
MKDIR_CALL='mkdir'
test "$SUDO" = 'y' && MKDIR_CALL="$SUDO_CALL $MKDIR_CALL"
# Mounting binfmt if necessary.
binfmt_mount "$MOUNT_CALL" "$ECHO_CALL"
# Mounting proc and dev. This is needed for executing scriptlets using qemu.
for dir in proc dev; do
debug "Creating $dir directory under $DESTDIR."
debug "$MKDIR_CALL -p \"$DESTDIR/$dir\" &>/dev/null"
$MKDIR_CALL -p "$DESTDIR/$dir" &>/dev/null
test $? -ne 0 && error "Failed to create $dir directory under $DESTDIR."
done
for dir in proc dev; do
debug "Mounting $dir under new root."
debug "$MOUNT_CALL -o bind /$dir \"$DESTDIR/$dir\" &>/dev/null"
$MOUNT_CALL -o bind /$dir "$DESTDIR/$dir" &>/dev/null
test $? -ne 0 && error "Failed to bind $dir to $DESTDIR/$dir."
CLEANUP=("M:$DESTDIR/$dir" ${CLEANUP[*]})
done
# Set correct umask
debug "Setting umask to 022."
umask 022 &>/dev/null
test $? -ne 0 && error "Failed to set umask to 022."
# Creating pacman's working directory
debug "Creating pacman's working directory."
debug "$MKDIR_CALL -p \"$DESTDIR/var/lib/pacman\" &>/dev/null"
$MKDIR_CALL -p "$DESTDIR/var/lib/pacman" &>/dev/null
test $? -ne 0 && error "Failed to create pacman's working directory."
# Preparing pacman call
PACMAN_FLAGS="-r $DESTDIR --config $CONFIG --noconfirm --noprogressbar"
PACMAN_TARGETS="${TARGETS[*]}"
PACMAN_CALL="$PACMAN"
test "$SUDO" = 'y' && PACMAN_CALL="$SUDO_CALL $PACMAN_CALL"
test "$BUILD" = 'y' && PACMAN_TARGETS="base-devel $PACMAN_TARGETS"
PACMAN_FLAGS="$PACMAN_FLAGS $PACMAN_EXTRA"
debug "PACMAN_FLAGS = $PACMAN_FLAGS"
debug "PACMAN_TARGETS = $PACMAN_TARGETS"
debug "${CONFIG}:"
cat "$CONFIG" | while read ln; do
debug "$ln"
done
# Installing qemu (for chrooting) and gcc-libs (for shared libs)
debug "Installing qemu and gcc-libs."
debug "$PACMAN_CALL $PACMAN_FLAGS -Sy --noscriptlet --nodeps qemu gcc-libs"
$PACMAN_CALL $PACMAN_FLAGS -Sy --noscriptlet --nodeps qemu gcc-libs
test $? -ne 0 && error "Failed to install qemu or gcc-libs."
# Installing base and possibly base-devel.
debug "Installing base system."
debug "$PACMAN_CALL $PACMAN_FLAGS -Sy $PACMAN_TARGETS"
$PACMAN_CALL $PACMAN_FLAGS -Sy $PACMAN_TARGETS
test $? -ne 0 && error "Failed to install base or possibly base-devel."
# Removing qemu again if necessary.
if [ "$BUILD" != 'y' ]; then
debug "Removing qemu from new root."
debug "$CHROOT_CALL $DESTDIR pacman -Rns --noconfirm --noprogressbar qemu"
$CHROOT_CALL $DESTDIR pacman -Rns --noconfirm --noprogressbar qemu
test $? -ne 0 && error "Failed to remove qemu."
fi
doCleanup
exit 0
# vim: set ft=sh ts=2 sw=2 et: