a287be3739d8654a50ce7b49ef4bb3a700da6c19
[distorted-chroot] / bin / update-cross-tools
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 --------------------------------------------------