Commit | Line | Data |
---|---|---|
3e5b03e2 MW |
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 | gnupg 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/ gpg gpgv gpgconf kbxutil watchgnupg | |
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 -------------------------------------------------- |