chiark / gitweb /
More work in progress.
[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
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 --------------------------------------------------