Makefile: Abolish `$(HERE)' as a bad idea.
[distorted-chroot] / bin / install-cross-tools
1 #! /bin/sh -e
2 ###
3 ### Replace common tools in foreign chroots with native versions
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 ## Parse the command-line.
30 badp=nil
31 case $# in 2) ;; *) badp=t ;; esac
32 case $badp in t) echo >&2 "usage: $0 DIST ARCH"; exit 2 ;; esac
33 d=$1 a=$2
34
35 ## Figure out of all the architecture names.
36 mymulti=$(dpkg-architecture -a$TOOLSARCH -qDEB_HOST_MULTIARCH)
37 gnuarch=$(dpkg-architecture -A$a -qDEB_TARGET_GNU_TYPE)
38 qarch=nil qhost=nil
39 for fa in $FOREIGN_ARCHS; do
40 case $fa in
41 "$a")
42 eval qarch=\$${a}_QEMUARCH qhost=\$${a}_QEMUHOST
43 break ;;
44 esac
45 done
46 case $qarch,$qhost in
47 nil,* | *,nil) echo >&2 "$0: not a foreign architecture"; exit 2 ;;
48 esac
49
50 ## Make sure we have the tools we need.
51 crossdir=/usr/local.schroot/cross/$d-$TOOLSARCH
52 my_crossdir=$LOCAL/${crossdir#/usr/local.schroot/}
53 qemudir=/usr/local.schroot/cross/$d-$qhost/QEMU
54 my_qemudir=$LOCAL/${qemudir#/usr/local.schroot/}
55 if ! [ -d $my_crossdir ]; then
56 echo 2>&1 "$0: no tree for \`$d-$TOOLSARCH'"; exit 2
57 fi
58 if ! [ -d $my_qemudir ]; then
59 echo 2>&1 "$0: no tree for \`$d-$qhost'"; exit 2
60 fi
61
62 ## Open a session to the target chroot.
63 sess=$(schroot -bcsource:$LVPREFIX$d-$a)
64 root=/schroot/$sess/fs
65
66 ## Abuse `/mnt/' as a temporary staging area. This saves us from clobbering
67 ## the chroot with weird directories.
68 schroot -uroot -rc$sess -- sh -ec '
69 if ! mountpoint -q /mnt; then
70 mount -ttmpfs -omode=700,uid=0,gid=0 private /mnt
71 fi'
72
73 ## Work through all of the tools we're interested in, to decide what we need
74 ## to do with it. Make lists:
75 ##
76 ## * `DIVERT.want' lists all of the filenames which need dpkg diversions to
77 ## prevent foreign versions of the tools from clobbering our native
78 ## versions.
79 ##
80 ## * `LINK'.want' lists all of the paths which need symbolic links into the
81 ## cross-tools trees, together with the link destinations.
82 { echo $qemudir/qemu-$qarch-static
83 echo $crossdir/lib/$mymulti
84 echo $crossdir/usr/lib/$mymulti
85 echo $crossdir/usr/lib/gcc-cross
86 find $my_crossdir $my_crossdir/TOOLCHAIN/$gnuarch \
87 \( \( -path "*/QEMU" -o -path "*/TOOLCHAIN" -o \
88 -path "*/lib/$mymulti" -o \
89 -path "*/lib/gcc-cross" \) -prune \) -o \
90 \( ! -type d -print \)
91 } | sed "s\a^$LOCAL/\a/usr/local.schroot/\a" | while read t; do
92 case $t in
93 $qemudir/*)
94 s=/usr/bin/${t#$qemudir/} ;;
95 $crossdir/TOOLCHAIN/$gnuarch/*)
96 s=/usr/bin/${t#$crossdir/TOOLCHAIN/$gnuarch/} ;;
97 *)
98 s=${t#$crossdir} ;;
99 esac
100 if [ -L $t ]; then t=$(readlink $t); fi
101 if [ -d $t ]; then act=LINK; else act=DIVERT; fi
102 echo $act $s $t
103 done >$root/mnt/ALL.want
104 sed -n '/^DIVERT \(.*\) .*$/s//\1/p' $root/mnt/ALL.want | \
105 sort >$root/mnt/DIVERT.want
106 sed -n '/^\(DIVERT\|LINK\) /s///p' $root/mnt/ALL.want | \
107 sort >$root/mnt/LINK.want
108
109 ## Make a list, `DIVERT.have', of paths which already have diversions, and a
110 ## list `LINK.have' of symbolic links into the cross-tools trees. The
111 ## layouts of these files match the `.want' files we just made.
112 schroot -uroot -rc$sess -- sh -ec '
113 dpkg-divert --list |
114 sed -n "/^diversion of \(.*\) to .* by install-cross-tools\$/s//\1/p" | \
115 sort >/mnt/DIVERT.have
116 { find / -xdev -lname "/usr/local.schroot/cross/*" -printf "%p %l\n"
117 while read s _; do
118 if ! [ -L "$s" ]; then continue; fi
119 t=$(readlink $s)
120 case $t in /usr/local.schroot/cross/*) continue ;; esac
121 echo "$s $t"
122 done </mnt/LINK.want >/dev/null
123 } | sort >/mnt/LINK.have'
124
125 ## Add diversions for the paths which need one, but don't have one. There's
126 ## a hack here because the `--no-rename' option was required in the same
127 ## version in which is was introduced, so there's no single incantation that
128 ## will work across the boundary.
129 schroot -uroot -rc$sess -- sh -ec '
130 a=$1
131
132 if dpkg-divert >/dev/null 2>&1 --no-rename --help
133 then no_rename=--no-rename
134 else no_rename=
135 fi
136
137 comm -13 /mnt/DIVERT.have /mnt/DIVERT.want | while read i; do
138 dpkg-divert --package "install-cross-tools" $no_rename \
139 --divert "$i.$a" --add "$i"
140 done' - $a
141
142 ## Go through each diverted tool, and, if it hasn't been moved aside, then
143 ## /link/ it across now. If we rename it, then the chroot will stop working
144 ## -- which is why we didn't allow `dpkg-divert' to do the rename. We can
145 ## tell a tool that hasn't been moved, because it's a symlink into one of the
146 ## cross trees.
147 while read i; do
148 if [ -e $root$i ] && ! [ -e $root$i.$a ]; then
149 if [ -L $root$i ]; then
150 t=$(readlink $root$i)
151 case $t in
152 $crossdir/* | $qemudir/* | /usr/local.schroot/qemu/*) continue ;;
153 esac
154 if [ -L $crossdir$i ]; then
155 u=$(readlink $crossdir$i)
156 case $t in "$u") continue ;; esac
157 fi
158 fi
159 echo >&2 "$0: preserve old $i"
160 ln $root$i $root$i.$a
161 fi
162 done <$root/mnt/DIVERT.want
163
164 ## Update all of the symbolic links which are currently wrong: add links
165 ## which are missing, delete ones which are obsolete, and update ones which
166 ## have the wrong target.
167 join -j1 -a1 -a2 -e- -o"0 1.2 2.2" \
168 $root/mnt/LINK.have $root/mnt/LINK.want |
169 while read s t0 t1; do
170 case $t1 in
171 "$t0")
172 continue
173 ;;
174 -)
175 echo >&2 "$0: remove obsolete link $s -> $t0"
176 rm -f $root$s
177 ;;
178 *)
179 case $s in */*) mkdir -p $root${s%/*} ;; esac
180 rm -f $root$s.new
181 ln -s $t1 $root$s.new
182 echo >&2 "$0: link $s -> $t1"
183 mv -T $root$s.new $root$s
184 ;;
185 esac
186 done
187
188 ## Remove diversions from paths which don't need them any more. Here it's
189 ## safe to rename, because either the tool isn't there, in which case it
190 ## obviously wasn't important, or it is, and `dpkg-divert' will atomically
191 ## replace our link with the foreign version.
192 schroot -uroot -rc$sess -- sh -ec '
193 a=$1
194 comm -23 /mnt/DIVERT.have /mnt/DIVERT.want | while read i; do
195 dpkg-divert --package "install-cross-tools" --rename \
196 --divert "$i.$a" --remove "$i"
197 done' - $a
198
199 ## Close the session.
200 schroot -ec$sess
201
202 ###----- That's all, folks --------------------------------------------------