| 1 | #! /bin/sh -e |
| 2 | ### |
| 3 | ### Fetch native versions of tools for insertion into foreign chroots |
| 4 | ### |
| 5 | ### (c) 2018 Mark Wooding |
| 6 | ### |
| 7 | |
| 8 | ###----- Licensing notice --------------------------------------------------- |
| 9 | ### |
| 10 | ### This file is part of the distorted.org.uk chroot maintenance tools. |
| 11 | ### |
| 12 | ### distorted-chroot is free software: you can redistribute it and/or |
| 13 | ### modify it under the terms of the GNU General Public License as |
| 14 | ### published by the Free Software Foundation; either version 2 of the |
| 15 | ### License, or (at your option) any later version. |
| 16 | ### |
| 17 | ### distorted-chroot is distributed in the hope that it will be useful, |
| 18 | ### but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | ### General Public License for more details. |
| 21 | ### |
| 22 | ### You should have received a copy of the GNU General Public License |
| 23 | ### along with distorted-chroot. If not, write to the Free Software |
| 24 | ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| 25 | ### USA. |
| 26 | |
| 27 | . state/config.sh # @@@config@@@ |
| 28 | |
| 29 | ###-------------------------------------------------------------------------- |
| 30 | ### Utilities. |
| 31 | |
| 32 | chase_link () { |
| 33 | p=$1 d= |
| 34 | ## Copy an absolute path P from the donor tree `$root/' into the |
| 35 | ## cross-tools tree `$crossnew/'. If resolving P involves traversing a |
| 36 | ## symbolic link, then ensure that the pieces of filesystem it directs us |
| 37 | ## to are also copied. |
| 38 | |
| 39 | ## Work through the remaining components of the path. |
| 40 | while :; do |
| 41 | |
| 42 | ## Analyse the first remaining component of the path P. |
| 43 | case $p in |
| 44 | |
| 45 | ## It's empty. We're done. |
| 46 | "") break ;; |
| 47 | |
| 48 | ## A redundant `/' or `./'. Skip it. |
| 49 | "/"*) p=${p#/} ;; |
| 50 | "./"*) p=${p#./} ;; |
| 51 | |
| 52 | ## A `../'. Strip off the trailing component of D. |
| 53 | "../"*) |
| 54 | p=${p#../} |
| 55 | case $d in */*) d=${d%/*} ;; *) d= ;; esac |
| 56 | ;; |
| 57 | |
| 58 | ## Something else. Transfer the component name to D. |
| 59 | *) |
| 60 | case $p in */*) f=${p%%/*} p=${p#*/} ;; *) f=$p p="" ;; esac |
| 61 | d=${d:+$d/}$f |
| 62 | ;; |
| 63 | esac |
| 64 | |
| 65 | ## If D doesn't refer to a file in the cross-tools tree, then maybe it |
| 66 | ## refers to something in the donor tree. Find out what, and copy it |
| 67 | ## into the cross-tools tree. |
| 68 | if ! [ -e "$crossnew$d" ] && ! [ -L "$crossnew$d" ]; then |
| 69 | if [ -d "$root/$d" ] && ! [ -L "$root/$d" ]; then |
| 70 | mkdir "$crossnew$d" |
| 71 | else |
| 72 | echo >&2 "$0: copy /$d to satisfy symlinks" |
| 73 | rsync -aHR $root/./$d $crossnew |
| 74 | fi |
| 75 | fi |
| 76 | |
| 77 | ## If D refers to a symbolic link, then append the link target to P, so |
| 78 | ## that we can make sure we copy the target. |
| 79 | if [ -L "$crossnew$d" ]; then |
| 80 | t=$(readlink "$crossnew$d") |
| 81 | case $t in /*) t=${t#/} d= ;; esac |
| 82 | case $d in */*) d=${d%/*} ;; *) d= ;; esac |
| 83 | p=$t${p:+/$p} |
| 84 | fi |
| 85 | done |
| 86 | } |
| 87 | |
| 88 | ###-------------------------------------------------------------------------- |
| 89 | ### Main program. |
| 90 | |
| 91 | ## Parse the command line. |
| 92 | badp=nil |
| 93 | case $# in 2) ;; *) badp=t ;; esac |
| 94 | case $badp in t) echo >&2 "usage: $0 DIST MYARCH"; exit 2 ;; esac |
| 95 | d=$1 myarch=$2 |
| 96 | |
| 97 | ## Keep track of our original stdout. |
| 98 | exec 3>&1 |
| 99 | |
| 100 | ## Figure out derived architecture names. |
| 101 | mymulti=$(dpkg-architecture -a$myarch -qDEB_HOST_MULTIARCH) |
| 102 | |
| 103 | ## First, set `cross_archs' as a list of GNUish names for our supported |
| 104 | ## foreign architectures. |
| 105 | cross_archs="arm-linux-gnueabi arm-linux-gnueabihf aarch64-linux-gnu" |
| 106 | |
| 107 | ## Make a list of extra packages we'll need to install to obtain our tools. |
| 108 | cross_pkgs=" |
| 109 | apt bash ccache coreutils dash eatmydata fakeroot findutils |
| 110 | gpgv gzip m4 make mawk qemu-user-static sed tar xz-utils" |
| 111 | for a in $cross_archs; do |
| 112 | for i in gcc g++ binutils; do |
| 113 | cross_pkgs="$cross_pkgs $i-$a" |
| 114 | done |
| 115 | done |
| 116 | cross_pkgs=$(echo $cross_pkgs) |
| 117 | |
| 118 | ## Make an enormous shopping list of paths. |
| 119 | ## |
| 120 | ## The `wanted' list consists of two kinds of items: an absolute path names a |
| 121 | ## prefix (not necessarily a directory name) to be attached to the following |
| 122 | ## relative names, up to the end of the list or the next absolute path. |
| 123 | wanted=" |
| 124 | /usr/bin/ apt apt-cache apt-config apt-get apt-key apt-mark |
| 125 | /usr/lib/apt/ methods/ solvers/ |
| 126 | |
| 127 | /bin/ cat chgrp chown cp date dd df dir echo false ln ls mkdir |
| 128 | mknod mktemp mv pwd readlink rm rmdir sleep stty sync touch |
| 129 | true uname vdir |
| 130 | /usr/bin/ [ arch b2sum base32 base64 basename chcon cksum comm |
| 131 | csplit cut dircolors dirname du env expand expr factor fmt |
| 132 | fold groups head hostid id install join link logname md5sum |
| 133 | mkfifo nice nl nohup nproc numfmt od paste pathchk pinky pr |
| 134 | printenv printf ptx realpath runcon seq sha1sum sha224sum |
| 135 | sha256sum sha384sum sha512sum shred shuf sort split stat |
| 136 | stdbuf sum tac tail tee test timeout tr truncate tsort tty |
| 137 | unexpand uniq unlink users wc who whoami yes |
| 138 | /usr/lib/$mymulti/ coreutils/ |
| 139 | |
| 140 | /lib/$mymulti/ libnss_*.so.* |
| 141 | |
| 142 | /usr/bin/ gpgv |
| 143 | |
| 144 | /usr/bin/ qemu-*-static |
| 145 | |
| 146 | /bin/ bash dash gzip sed tar |
| 147 | /usr/bin/ ccache find m4 make mawk xargs xz |
| 148 | /usr/lib/$mymulti/ libeatmydata.so* libfakeroot/ |
| 149 | |
| 150 | /etc/ld.so.conf.d/ $mymulti.conf fakeroot*.conf" |
| 151 | |
| 152 | for a in $cross_archs; do |
| 153 | wanted="$wanted |
| 154 | |
| 155 | /usr/bin/$a- addr2line ar as c++filt dwp elfedit gprof ld ld.* |
| 156 | nm objcopy objdump ranlib readelf size strings strip |
| 157 | |
| 158 | /usr/bin/$a- cpp gcc g++ gcov gcov-dump gcov-tool gprof |
| 159 | gcc-ar gcc-nm gcc-ranlib |
| 160 | /usr/lib/gcc-cross/$a/ ..." |
| 161 | done |
| 162 | wanted=$(echo $wanted) |
| 163 | |
| 164 | ## Figure out how to recognize dynamic executables. |
| 165 | case $myarch in |
| 166 | i386) elfsig=7f454c46010101??0000000000000000????0300 ;; |
| 167 | amd64) elfsig=7f454c46020101??0000000000000000????3e00 ;; |
| 168 | *) echo >&2 "$0: unsupported local arch \`$myarch'"; exit 2 ;; |
| 169 | esac |
| 170 | |
| 171 | ## Open a session to the donor chroot. |
| 172 | echo >&2 "$0: create $d snapshot" |
| 173 | sess=$(schroot -bc$LVPREFIX$d-$myarch 3>&-) |
| 174 | |
| 175 | ## Make sure the donor tree is up-to-date, and install the extra packages we |
| 176 | ## need. |
| 177 | schroot -uroot -rc$sess -- eatmydata sh -ec " |
| 178 | apt-get update |
| 179 | apt-get -y upgrade |
| 180 | apt-get -y install $cross_pkgs" |
| 181 | |
| 182 | ## Establish some pathnames. Prepare a place for our cross-tools tree. |
| 183 | crossdir=$LOCAL/cross/$d-$myarch/ |
| 184 | crossold=${crossdir%/}.old/ crossnew=${crossdir%/}.new/ |
| 185 | root=/schroot/$sess/fs |
| 186 | rm -rf $crossnew; mkdir -p $crossnew |
| 187 | |
| 188 | ## Work through the shopping list, copying the things it names into the |
| 189 | ## cross-tools tree. |
| 190 | dir=/ |
| 191 | for i in $wanted; do |
| 192 | case $i in |
| 193 | /*) |
| 194 | dir=$i |
| 195 | ;; |
| 196 | *) |
| 197 | case $i in ...) f=$dir ;; *) f=$dir$i ;; esac |
| 198 | echo >&2 "$0: copy $f" |
| 199 | rsync -aHR $root/.$f $crossnew |
| 200 | ;; |
| 201 | esac |
| 202 | done |
| 203 | |
| 204 | ## Chase links in the new tree, copying extra stuff that we'll need. |
| 205 | find $crossnew -xtype l -print | while read i; do |
| 206 | chase_link ${i#$crossnew} |
| 207 | done |
| 208 | |
| 209 | ## Search the new tree for ELF binaries, and build a list of them in |
| 210 | ## `QUEUE.in'. |
| 211 | find $crossnew -type f -print | while read i; do |
| 212 | sig=$(head -c20 "$i" | bincode -e -m0 -flowerc hex) |
| 213 | case $sig in $elfsig) echo "$i" ;; esac |
| 214 | done >$root/private/QUEUE.in |
| 215 | |
| 216 | while [ -s $root/private/QUEUE.in ]; do |
| 217 | ## Work through the ELF binaries in `QUEUE.in', determining which shared |
| 218 | ## libraries they'll need. Write the list of dependencies to `QUEUE.out' |
| 219 | schroot -uroot -rc$sess -- eatmydata sh -ec ' |
| 220 | prog=$1 |
| 221 | while read i; do |
| 222 | echo >&2 "$prog: scanning binary $i" |
| 223 | ldd "$i" | while read a b c d; do |
| 224 | case $a:$b:$c:$d in |
| 225 | not:a:dynamic:executable) ;; |
| 226 | statically:linked::) ;; |
| 227 | /*) echo "$a" ;; |
| 228 | *:=\>:/*) echo "$c" ;; |
| 229 | linux-*) ;; |
| 230 | *) echo >&2 "$i: unable to find $a"; exit 2 ;; |
| 231 | esac |
| 232 | done |
| 233 | done </private/QUEUE.in >/private/QUEUE.out' - "$0" |
| 234 | |
| 235 | ## Work through the shared libraries in `QUEUE.out', copying them to the |
| 236 | ## cross-tools tree if they're not there already. Add the new ones to a |
| 237 | ## new `QUEUE.in' file to scan them in turn. |
| 238 | while read i; do |
| 239 | if [ -e "$crossnew$i" ] || [ -L "$crossnew$i" ] |
| 240 | then continue; fi |
| 241 | if [ -d "$root$i" ]; then continue; fi |
| 242 | echo >&2 "$0: copy $i" |
| 243 | rsync -aHR $root/.$i $crossnew >&3 |
| 244 | chase_link $i >&3 |
| 245 | sig=$(head -c20 $crossnew$i | bincode -e -m0 -flowerc hex) |
| 246 | case $sig in $elfsig) echo "$i" ;; esac |
| 247 | done <$root/private/QUEUE.out >$root/private/QUEUE.in |
| 248 | done |
| 249 | |
| 250 | ## Set up the cross-compiler. This is rather hairy. |
| 251 | echo >&2 "$0: establish TOOLCHAIN" |
| 252 | for a in $cross_archs; do |
| 253 | tooldir=$crossnew/TOOLCHAIN/$a |
| 254 | mkdir -p $tooldir |
| 255 | for i in $crossnew/usr/bin/$a-*; do |
| 256 | t=${i#$crossnew/usr/bin/} |
| 257 | mv $i $tooldir/$t |
| 258 | ln -s $t $tooldir/${t#$a-} |
| 259 | done |
| 260 | done |
| 261 | mkdir $crossnew/TOOLCHAIN/lib |
| 262 | ln -s ../../usr/lib/gcc-cross $crossnew/TOOLCHAIN/lib/ |
| 263 | |
| 264 | ## Set up the emulator. |
| 265 | echo >&2 "$0: establish QEMU" |
| 266 | mkdir $crossnew/QEMU |
| 267 | mv $crossnew/usr/bin/qemu-*-static $crossnew/QEMU/ |
| 268 | |
| 269 | ## We're done. Remove the snapshot, and replace the old cross-tools tree |
| 270 | ## with our new one. |
| 271 | echo >&2 "$0: remove snapshot" |
| 272 | schroot -ec$sess 3>&- |
| 273 | if [ -d $crossdir ]; then mv $crossdir $crossold; fi |
| 274 | mv $crossnew $crossdir; rm -rf $crossold |
| 275 | echo >&2 "$0: committed $crossdir" |
| 276 | |
| 277 | ###----- That's all, folkd -------------------------------------------------- |