summaryrefslogtreecommitdiffstats
path: root/build/install-chroot.sh
blob: ad0dafadcab612e5ea021956bd590e767968a083 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/bin/bash -e

# Copyright (c) 2010 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# This script installs Debian-derived distributions in a chroot environment.
# It can for example be used to have an accurate 32bit build and test
# environment when otherwise working on a 64bit machine.
# N. B. it is unlikely that this script will ever work on anything other than a
# Debian-derived system.

# Check that we are running as a regular user
[ "$(id -nu)" = root ] && {
  echo "Run this script as a regular user and provide your \"sudo\""           \
       "password if requested" >&2
  exit 1
}
mkdir -p "$HOME/chroot/"

# Error handler
trap 'exit 1' INT TERM QUIT
trap 'sudo apt-get clean; tput bel; echo; echo Failed' EXIT

# Install any missing applications that this script relies on. If these packages
# are already installed, don't force another "apt-get install". That would
# prevent them from being auto-removed, if they ever become eligible for that.
# And as this script only needs the packages once, there is no good reason to
# introduce a hard dependency on things such as dchroot and debootstrap.
dep=
for i in dchroot debootstrap; do
  [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
done
[ -n "$dep" ] && sudo apt-get -y install $dep
sudo apt-get -y install schroot

# Create directory for chroot
sudo mkdir -p /var/lib/chroot

# Find chroot environments that can be installed with debootstrap
targets="$(cd /usr/share/debootstrap/scripts
           ls | grep '^[a-z]*$')"

# Ask user to pick one of the available targets
echo "The following targets are available to be installed in a chroot:"
j=1; for i in $targets; do
  printf '%4d: %s\n' "$j" "$i"
  j=$(($j+1))
done
while :; do
  printf "Which target would you like to install: "
  read n
  [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break
done
j=1; for i in $targets; do
  [ "$j" -eq "$n" ] && { distname="$i"; break; }
  j=$(($j+1))
done

# On x86-64, ask whether the user wants to install x86-32 or x86-64
archflag=
arch=
if [ "$(uname -m)" = x86_64 ]; then
  while :; do
    echo "You are running a 64bit kernel. This allows you to install either a"
    printf "32bit or a 64bit chroot environment. %s"                           \
           "Which one do you want (32, 64) "
    read arch
    [ "${arch}" == 32 -o "${arch}" == 64 ] && break
  done
  [ "${arch}" == 32 ] && archflag="--arch i386" || archflag="--arch amd64"
  arch="${arch}bit"
fi
target="${distname}${arch}"

# Don't overwrite an existing installation
[ -d /var/lib/chroot/"${target}" ] && {
  echo "This chroot already exists on your machine." >&2
  echo "Delete /var/lib/chroot/${target} if you want to start over." >&2
  exit 1
}
sudo mkdir -p /var/lib/chroot/"${target}"

# Remove stale entry from /etc/schroot/schroot.conf. Entries start
# with the target name in square brackets, followed by an arbitrary
# number of lines. The entry stops when either the end of file has
# been reached, or when the beginning of a new target is encountered.
# This means, we cannot easily match for a range of lines in
# "sed". Instead, we actually have to iterate over each line and check
# whether it is the beginning of a new entry.
sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p'       \
         /etc/schroot/schroot.conf

# Download base system. This takes some time
grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null &&
 mirror="http://archive.ubuntu.com/ubuntu" ||
 mirror="http://ftp.us.debian.org/debian"
 sudo debootstrap ${archflag} "${distname}" /var/lib/chroot/"${target}"        \
                  "$mirror"

# Add new entry to /etc/schroot/schroot.conf
grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null &&
  brand="Ubuntu" || brand="Debian"
sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
[${target%bit}]
description=${brand} ${distname} ${arch}
type=directory
directory=/var/lib/chroot/${target}
priority=3
users=root
groups=admin
root-groups=admin
personality=linux$([ "${arch}" != 64bit ] && echo 32)
script-config=script-${target}

EOF

# Set up a special directory that changes contents depending on the target
# that is executing.
sed '/^FSTAB=/s,/mount-defaults",/mount-'"${target}"'",'                       \
         /etc/schroot/script-defaults |
  sudo sh -c 'cat >/etc/schroot/script-'"${target}"
sudo cp /etc/schroot/mount-defaults /etc/schroot/mount-"${target}"
echo "$HOME/chroot/.${target} $HOME/chroot none rw,bind 0 0" |
  sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
mkdir -p "$HOME/chroot/.${target}"

# Install a helper script to launch commands in the chroot
sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<EOF
#!/bin/bash
if [ \$# -eq 0 ]; then
  exec schroot -c ${target%bit} -p
else
  p="\$1"; shift
  exec schroot -c ${target%bit} -p "\$p" -- "\$@"
fi
exit 1
EOF
sudo chown root:root /usr/local/bin/"${target%bit}"
sudo chmod 755 /usr/local/bin/"${target%bit}"

# Add a few more repositories to the chroot
[ -r /var/lib/chroot/${target}/etc/apt/sources.list ] &&
sudo sed -i 's/ main$/ main restricted universe multiverse/
             p
             t1
             d
          :1;s/^deb/deb-src/
             t
             d' /var/lib/chroot/${target}/etc/apt/sources.list

# Update packages
sudo schroot -c "${target%bit}" -p -- /bin/sh -c '
  apt-get update; apt-get -y dist-upgrade' || :

# Install a couple of missing packages
for i in debian-keyring ubuntu-keyring locales sudo; do
  [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
    sudo schroot -c "${target%bit}" -p -- apt-get -y install "$i" || :
done

# Configure locales
sudo schroot -c "${target%bit}" -p -- /bin/sh -c '
  l='"${LANG:-en_US}"'; l="${l%%.*}"
  [ -r /etc/locale.gen ] &&
    sed -i "s/^# \($l\)/\1/" /etc/locale.gen
  locale-gen $LANG en_US en_US.UTF-8' || :

# Configure "sudo" package
sudo schroot -c "${target%bit}" -p -- /bin/sh -c '
  egrep '"'^$(id -nu) '"' /etc/sudoers >/dev/null 2>&1 ||
  echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'

# Install a few more commonly used packages
sudo schroot -c "${target%bit}" -p -- apt-get -y install                       \
  autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool     \
  strace

# If running a 32bit environment on a 64bit machine, install a few binaries
# as 64bit.
if [ "${arch}" = 32bit ] && file /bin/bash 2>/dev/null | grep -q x86-64; then
  sudo schroot -c "${target%bit}" -p -- apt-get -y install                     \
    lib64expat1 lib64ncurses5 lib64readline6 lib64z1
  dep=
  for i in binutils gdb strace; do
    [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
  done
  [ -n "$dep" ] && sudo apt-get -y install $dep
  sudo cp /usr/bin/gdb /var/lib/chroot/${target}/usr/local/bin/
  sudo cp /usr/bin/ld /var/lib/chroot/${target}/usr/local/bin/
  for i in libbfd libpython; do
    lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
           grep "$i" | awk '{ print $3 }')"
    if [ -n "$lib" -a -r "$lib" ]; then
      sudo cp "$lib" /var/lib/chroot/${target}/usr/lib64/
    fi
  done
  for lib in libssl libcrypt; do
    sudo cp /usr/lib/$lib* /var/lib/chroot/${target}/usr/lib64/ || :
  done
fi

# Clean up package files
sudo schroot -c "${target%bit}" -p -- apt-get clean
sudo apt-get clean

# Let the user know what we did
trap '' INT TERM QUIT
trap '' EXIT
cat <<EOF


Successfully installed ${distname} ${arch}

You can run programs inside of the chroot by invoking the "${target%bit}"
command.

Your home directory is shared between the host and the chroot. But I configured
$HOME/chroot to be private to the chroot environment. You can use it
for files that need to differ between environments.
EOF