+#! /bin/sh -e
+###
+### Fetch native versions of tools for insertion into foreign chroots
+###
+### (c) 2018 Mark Wooding
+###
+
+###----- Licensing notice ---------------------------------------------------
+###
+### This file is part of the distorted.org.uk chroot maintenance tools.
+###
+### distorted-chroot 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.
+###
+### distorted-chroot 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 distorted-chroot. If not, write to the Free Software
+### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+### USA.
+
+. state/config.sh # @@@config@@@
+
+###--------------------------------------------------------------------------
+### Utilities.
+
+chase_link () {
+ p=$1 d=
+ ## Copy an absolute path P from the donor tree `$root/' into the
+ ## cross-tools tree `$crossnew/'. If resolving P involves traversing a
+ ## symbolic link, then ensure that the pieces of filesystem it directs us
+ ## to are also copied.
+
+ ## Work through the remaining components of the path.
+ while :; do
+
+ ## Analyse the first remaining component of the path P.
+ case $p in
+
+ ## It's empty. We're done.
+ "") break ;;
+
+ ## A redundant `/' or `./'. Skip it.
+ "/"*) p=${p#/} ;;
+ "./"*) p=${p#./} ;;
+
+ ## A `../'. Strip off the trailing component of D.
+ "../"*)
+ p=${p#../}
+ case $d in */*) d=${d%/*} ;; *) d= ;; esac
+ ;;
+
+ ## Something else. Transfer the component name to D.
+ *)
+ case $p in */*) f=${p%%/*} p=${p#*/} ;; *) f=$p p="" ;; esac
+ d=${d:+$d/}$f
+ ;;
+ esac
+
+ ## If D doesn't refer to a file in the cross-tools tree, then maybe it
+ ## refers to something in the donor tree. Find out what, and copy it
+ ## into the cross-tools tree.
+ if ! [ -e "$crossnew$d" ] && ! [ -L "$crossnew$d" ]; then
+ if [ -d "$root/$d" ] && ! [ -L "$root/$d" ]; then
+ mkdir "$crossnew$d"
+ else
+ echo >&2 "$0: copy /$d to satisfy symlinks"
+ rsync -aHR $root/./$d $crossnew
+ fi
+ fi
+
+ ## If D refers to a symbolic link, then append the link target to P, so
+ ## that we can make sure we copy the target.
+ if [ -L "$crossnew$d" ]; then
+ t=$(readlink "$crossnew$d")
+ case $t in /*) t=${t#/} d= ;; esac
+ case $d in */*) d=${d%/*} ;; *) d= ;; esac
+ p=$t${p:+/$p}
+ fi
+ done
+}
+
+###--------------------------------------------------------------------------
+### Main program.
+
+## Parse the command line.
+badp=nil
+case $# in 2) ;; *) badp=t ;; esac
+case $badp in t) echo >&2 "usage: $0 DIST MYARCH"; exit 2 ;; esac
+d=$1 myarch=$2
+
+## Keep track of our original stdout.
+exec 3>&1
+
+## Figure out derived architecture names.
+mymulti=$(dpkg-architecture -a$myarch -qDEB_HOST_MULTIARCH)
+
+## First, set `cross_archs' as a list of GNUish names for our supported
+## foreign architectures.
+cross_archs="arm-linux-gnueabi arm-linux-gnueabihf aarch64-linux-gnu"
+
+## Make a list of extra packages we'll need to install to obtain our tools.
+cross_pkgs="
+ apt bash ccache coreutils dash eatmydata fakeroot findutils
+ gnupg gpgv gzip m4 make mawk qemu-user-static sed tar xz-utils"
+for a in $cross_archs; do
+ for i in gcc g++ binutils; do
+ cross_pkgs="$cross_pkgs $i-$a"
+ done
+done
+cross_pkgs=$(echo $cross_pkgs)
+
+## Make an enormous shopping list of paths.
+##
+## The `wanted' list consists of two kinds of items: an absolute path names a
+## prefix (not necessarily a directory name) to be attached to the following
+## relative names, up to the end of the list or the next absolute path.
+wanted="
+ /usr/bin/ apt apt-cache apt-config apt-get apt-key apt-mark
+ /usr/lib/apt/ methods/ solvers/
+
+ /bin/ cat chgrp chown cp date dd df dir echo false ln ls mkdir
+ mknod mktemp mv pwd readlink rm rmdir sleep stty sync touch
+ true uname vdir
+ /usr/bin/ [ arch b2sum base32 base64 basename chcon cksum comm
+ csplit cut dircolors dirname du env expand expr factor fmt
+ fold groups head hostid id install join link logname md5sum
+ mkfifo nice nl nohup nproc numfmt od paste pathchk pinky pr
+ printenv printf ptx realpath runcon seq sha1sum sha224sum
+ sha256sum sha384sum sha512sum shred shuf sort split stat
+ stdbuf sum tac tail tee test timeout tr truncate tsort tty
+ unexpand uniq unlink users wc who whoami yes
+ /usr/lib/$mymulti/ coreutils/
+
+ /lib/$mymulti/ libnss_*.so.*
+
+ /usr/bin/ gpg gpgv gpgconf kbxutil watchgnupg
+
+ /usr/bin/ qemu-*-static
+
+ /bin/ bash dash gzip sed tar
+ /usr/bin/ ccache find m4 make mawk xargs xz
+ /usr/lib/$mymulti/ libeatmydata.so* libfakeroot/
+
+ /etc/ld.so.conf.d/ $mymulti.conf fakeroot*.conf"
+
+for a in $cross_archs; do
+ wanted="$wanted
+
+ /usr/bin/$a- addr2line ar as c++filt dwp elfedit gprof ld ld.*
+ nm objcopy objdump ranlib readelf size strings strip
+
+ /usr/bin/$a- cpp gcc g++ gcov gcov-dump gcov-tool gprof
+ gcc-ar gcc-nm gcc-ranlib
+ /usr/lib/gcc-cross/$a/ ..."
+done
+wanted=$(echo $wanted)
+
+## Figure out how to recognize dynamic executables.
+case $myarch in
+ i386) elfsig=7f454c46010101??0000000000000000????0300 ;;
+ amd64) elfsig=7f454c46020101??0000000000000000????3e00 ;;
+ *) echo >&2 "$0: unsupported local arch \`$myarch'"; exit 2 ;;
+esac
+
+## Open a session to the donor chroot.
+echo >&2 "$0: create $d snapshot"
+sess=$(schroot -bc$LVPREFIX$d-$myarch 3>&-)
+
+## Make sure the donor tree is up-to-date, and install the extra packages we
+## need.
+schroot -uroot -rc$sess -- eatmydata sh -ec "
+ apt-get update
+ apt-get -y upgrade
+ apt-get -y install $cross_pkgs"
+
+## Establish some pathnames. Prepare a place for our cross-tools tree.
+crossdir=$LOCAL/cross/$d-$myarch/
+crossold=${crossdir%/}.old/ crossnew=${crossdir%/}.new/
+root=/schroot/$sess/fs
+rm -rf $crossnew; mkdir -p $crossnew
+
+## Work through the shopping list, copying the things it names into the
+## cross-tools tree.
+dir=/
+for i in $wanted; do
+ case $i in
+ /*)
+ dir=$i
+ ;;
+ *)
+ case $i in ...) f=$dir ;; *) f=$dir$i ;; esac
+ echo >&2 "$0: copy $f"
+ rsync -aHR $root/.$f $crossnew
+ ;;
+ esac
+done
+
+## Chase links in the new tree, copying extra stuff that we'll need.
+find $crossnew -xtype l -print | while read i; do
+ chase_link ${i#$crossnew}
+done
+
+## Search the new tree for ELF binaries, and build a list of them in
+## `QUEUE.in'.
+find $crossnew -type f -print | while read i; do
+ sig=$(head -c20 "$i" | bincode -e -m0 -flowerc hex)
+ case $sig in $elfsig) echo "$i" ;; esac
+done >$root/private/QUEUE.in
+
+while [ -s $root/private/QUEUE.in ]; do
+ ## Work through the ELF binaries in `QUEUE.in', determining which shared
+ ## libraries they'll need. Write the list of dependencies to `QUEUE.out'
+ schroot -uroot -rc$sess -- eatmydata sh -ec '
+ prog=$1
+ while read i; do
+ echo >&2 "$prog: scanning binary $i"
+ ldd "$i" | while read a b c d; do
+ case $a:$b:$c:$d in
+ not:a:dynamic:executable) ;;
+ statically:linked::) ;;
+ /*) echo "$a" ;;
+ *:=\>:/*) echo "$c" ;;
+ linux-*) ;;
+ *) echo >&2 "$i: unable to find $a"; exit 2 ;;
+ esac
+ done
+ done </private/QUEUE.in >/private/QUEUE.out' - "$0"
+
+ ## Work through the shared libraries in `QUEUE.out', copying them to the
+ ## cross-tools tree if they're not there already. Add the new ones to a
+ ## new `QUEUE.in' file to scan them in turn.
+ while read i; do
+ if [ -e "$crossnew$i" ] || [ -L "$crossnew$i" ]
+ then continue; fi
+ if [ -d "$root$i" ]; then continue; fi
+ echo >&2 "$0: copy $i"
+ rsync -aHR $root/.$i $crossnew >&3
+ chase_link $i >&3
+ sig=$(head -c20 $crossnew$i | bincode -e -m0 -flowerc hex)
+ case $sig in $elfsig) echo "$i" ;; esac
+ done <$root/private/QUEUE.out >$root/private/QUEUE.in
+done
+
+## Set up the cross-compiler. This is rather hairy.
+echo >&2 "$0: establish TOOLCHAIN"
+for a in $cross_archs; do
+ tooldir=$crossnew/TOOLCHAIN/$a
+ mkdir -p $tooldir
+ for i in $crossnew/usr/bin/$a-*; do
+ t=${i#$crossnew/usr/bin/}
+ mv $i $tooldir/$t
+ ln -s $t $tooldir/${t#$a-}
+ done
+done
+mkdir $crossnew/TOOLCHAIN/lib
+ln -s ../../usr/lib/gcc-cross $crossnew/TOOLCHAIN/lib/
+
+## Set up the emulator.
+echo >&2 "$0: establish QEMU"
+mkdir $crossnew/QEMU
+mv $crossnew/usr/bin/qemu-*-static $crossnew/QEMU/
+
+## We're done. Remove the snapshot, and replace the old cross-tools tree
+## with our new one.
+echo >&2 "$0: remove snapshot"
+schroot -ec$sess 3>&-
+if [ -d $crossdir ]; then mv $crossdir $crossold; fi
+mv $crossnew $crossdir; rm -rf $crossold
+echo >&2 "$0: committed $crossdir"
+
+###----- That's all, folkd --------------------------------------------------