| 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 -------------------------------------------------- |