#!/bin/sh prog=${0##*/} version=@VERSION@ cleanup() { cd / if [ -n "$uninstalls" ]; then apk del -q syslinux fi if [ -n "$umounts" ]; then umount $umounts fi } die() { echo "$@" >&2 cleanup exit 1 } # find device for mountpoint find_dev() { local mnt="${1%/}" # strip trailing / awk "\$2 == \"$mnt\" {print \$1}" /proc/mounts } # check if given device is on usb bus on_usb_bus() { local dev="$1" [ -e /sys/block/$dev ] || return 1 local sysdev=$(readlink -f /sys/block/$dev/device) test "${sysdev##*/usb[0-9]}" != "$sysdev" } # mount source as loopback and set srcdir mount_srcdir() { local srcmnt=${MNT:-/mnt} mount -o loop -t iso9660 "$src" $srcmnt \ || die "Failed to mount loopback $src" umounts="$srcmnt" srcdir="$srcmnt" if ! [ -f "$srcdir"/.alpine-release ]; then die "No .alpine-release found on image $src" fi } usage() { cat <<__EOF__ $prog $version usage: $prog [-hu] SOURCE [DEST] Copy the contents of SOURCE to DEST and make DEST bootable. SOURCE can be a directory or a ISO image. DEST can be a mounted directory or a device. If DEST is ommitted /media/usb will be used. Options: -f Force overwrite existing files. Will overwrite syslinux.cfg if upgrade. -h Show this help. -u Upgrade mode. Keep existing syslinux.cfg and don't run syslinux. -s Force run syslinux, even if upgrade mode. -v Verbose mode. Display whats going on. __EOF__ exit 1 } while getopts "fhusv" opt; do case "$opt" in f) force=1;; h) usage;; u) upgrade=1;; s) syslinux=1;; v) verbose=1;; esac done shift $(($OPTIND - 1)) src=${1} dest=${2:-/media/usb} [ -z "$src" ] && usage srcdir= # Find the srcdir or srcurl. mount loopback if needed if [ -f "$src"/.alpine-release ]; then srcdir="$src" else case "$src" in http://*|ftp://*) srcurl="$src";; *) mount_srcdir;; esac fi if [ -n "$srcdir" ]; then to_version=$(cat "$srcdir"/.alpine-release) fi # find target device if [ -d "$dest" ]; then dest=${dest%/} # strip trailing / if ! awk '{print $2}' /proc/mounts | grep -q "^$dest\$"; then mount "$dest" || die "Failed to mount $dest" umounts="$umounts $dest" fi destdir="$dest" dest=$(find_dev "$destdir") elif [ -b "$dest" ]; then destdir="/media/${dest##*/}" mkdir -p "$destdir" mount "$dest" "$destdir" || die "Failed to mount $dest on $destdir" umounts="$umounts $destdir" fi [ -n "$verbose" ] && echo "Using $dest as target (mounted on $destdir)" # find parent device (i.e sda) dev="$dest" while [ -L "$dev" ]; do dev=$(readlink -f $dev) done parent_dev=/dev/$(basename $(dirname /sys/block/*/$(basename $dev))) # check if this files exist and not in upgrade mode if [ -z "$upgrade" ] && [ -z "$force" ]; then for i in boot apks syslinux.cfg .alpine-release; do [ -e "$destdir"/$i ] && die "$destdir/$i already exists. Aborting" done fi # check if its same version if [ -n "$upgrade" ] && [ -e "$destdir"/.alpine-release ]; then from_version=$(cat "$destdir"/.alpine-release) if [ -z "$force" ] && [ -n "$to_version" ] && [ "$from_version" = "$to_version" ]; then die "Source and target seems to have same version ($from_version). Aborting." fi fi # Display what versions we are installing/upgrading if [ -n "$from_version" ]; then echo "Upgrading $dest from $from_version to $to_version" else echo "Copying $to_version to $dest (mounted on $destdir)" fi # remove partial upgrades if any. rm -rf "$destdir"/.new "$destdir"/.old mkdir -p "$destdir"/.new || die "Failed to create $destdir/.new" # check that we have the space we need # we calculate on MB since shell arthimetic gets problems with big disks # and bytes. free_blocks=$(stat -f -c "%f" "$destdir") block_size=$(stat -f -c "%s" "$destdir") blocks_per_mb=$(( 1024 * 1024 / $block_size)) available_space=$(( $free_blocks / $blocks_per_mb )) [ -n "$verbose" ] && echo "Available space: $available_space MiB" if [ -n "$srcdir" ]; then needed_space=$(cd "$srcdir" && du -m -s -c boot apks syslinux.cfg .alpine-release | awk '$2 == "total" {print $1}') [ -n "$verbose" ] && echo "Needed space: $needed_space MiB" [ $available_space -lt $needed_space ] \ && die "Not enough space on $destdir. Aborting." # copy the files to .new for i in boot apks syslinux.cfg .alpine-release; do [ -n "$verbose" ] && echo "Copying $srcdir/$i to $destdir/.new/" cp -a "$srcdir"/$i "$destdir"/.new/ done elif [ -n "$srcurl" ]; then cd "$destdir"/.new ${WGET:-wget} -O - "$srcurl" | uniso \ || die "Failed to download or extract $srcurl" fi # make sure files are really there before we replace existing [ -n "$verbose" ] && echo "Flushing cache..." sync [ -n "$verbose" ] && echo "Replacing existing files..." mkdir -p "$destdir"/.old || die "Failed to create $destdir/.old" # do we want keep existing syslinux.cfg? tomove="boot apks .alpine-release" if [ -n "$force" ] || ! [ -e "$destdir"/syslinux.cfg ]; then tomove="$tomove syslinux.cfg" # update syslinux.cfg unless device is on usb bus # this is so we can boot from CF's and harddisk if ! on_usb_bus $parent_dev; then [ -n "$verbose" ] && echo "Updating syslinux.cfg to use $dest" sed -i -e "s/usbdisk/${dest##*/}/g" \ "$destdir"/.new/syslinux.cfg fi fi # move current files to .old for i in $tomove; do if [ -e "$destdir"/$i ]; then mv "$destdir"/$i "$destdir"/.old/ || die "Failed to move $destdir/$i to $destdir/.old/" fi done # move .new to current for i in $tomove; do mv "$destdir"/.new/$i "$destdir"/ || die "Failed to move $destdir/.new/ to $destdir" done # cleanup [ -z "$keep_old" ] && rm -rf "$destdir"/.old "$destdir"/.new sync # If we only copy then we are done. if [ -n "$upgrade" ] && [ -z "$syslinux" ]; then cleanup exit 0 fi echo "Making $dest bootable..." if ! [ -x "$(which syslinux)" ]; then apk add -q syslinux || die "Failed to install syslinux" uninstalls="syslinux" fi syslinux $dest if [ -b $parent_dev ]; then dd if=/usr/share/syslinux/mbr.bin of=$parent_dev else echo "Warning: Could not find the parent device for $dest" fi cleanup sync