Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(562)

Side by Side Diff: build/install-chroot.sh

Issue 9702047: Lots of tweaks to the install-chroot.sh and install-build-deps.sh (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/install-build-deps.sh ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/bin/bash -e 1 #!/bin/bash -e
2 2
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 # This script installs Debian-derived distributions in a chroot environment. 7 # This script installs Debian-derived distributions in a chroot environment.
8 # It can for example be used to have an accurate 32bit build and test 8 # It can for example be used to have an accurate 32bit build and test
9 # environment when otherwise working on a 64bit machine. 9 # environment when otherwise working on a 64bit machine.
10 # N. B. it is unlikely that this script will ever work on anything other than a 10 # N. B. it is unlikely that this script will ever work on anything other than a
11 # Debian-derived system. 11 # Debian-derived system.
12 12
13 # Older Debian based systems had both "admin" and "adm" groups, with "admin"
14 # apparently being used in more places. Newer distributions have standardized
15 # on just the "adm" group. Check /etc/group for the prefered name of the
16 # administrator group.
17 admin=$(grep '^admin:' /etc/group >&/dev/null && echo admin || echo adm)
Michael Moss 2012/03/15 17:35:37 nit: 'grep -q' (and maybe -s) is preferred elsewhe
Markus (顧孟勤) 2012/03/15 18:20:10 Fair enough. Normally, I tend to avoid -q and -s,
18
13 usage() { 19 usage() {
14 echo "usage: ${0##*/} [-m mirror] [-g group,...] [-s] [-c]" 20 echo "usage: ${0##*/} [-m mirror] [-g group,...] [-s] [-c]"
21 echo "-b dir additional directories that should be bind mounted,"
22 echo ' or "NONE".'
23 echo " Default: if local filesystems present, ask user for help"
15 echo "-g group,... groups that can use the chroot unauthenticated" 24 echo "-g group,... groups that can use the chroot unauthenticated"
16 echo " Default: 'admin' and current user's group ('$(id -gn)')" 25 echo " Default: '${admin}' and current user's group ('$(id -gn)')"
26 echo "-l List all installed chroot environments"
17 echo "-m mirror an alternate repository mirror for package downloads" 27 echo "-m mirror an alternate repository mirror for package downloads"
18 echo "-s configure default deb-srcs" 28 echo "-s configure default deb-srcs"
19 echo "-c always copy 64bit helper binaries to 32bit chroot" 29 echo "-c always copy 64bit helper binaries to 32bit chroot"
20 echo "-h this help message" 30 echo "-h this help message"
21 } 31 }
22 32
23 process_opts() { 33 process_opts() {
24 local OPTNAME OPTIND OPTERR OPTARG 34 local OPTNAME OPTIND OPTERR OPTARG
25 while getopts ":g:m:sch" OPTNAME; do 35 while getopts ":b:g:lm:sch" OPTNAME; do
26 case "$OPTNAME" in 36 case "$OPTNAME" in
37 b)
38 if [ "${OPTARG}" = "NONE" -a -z "${bind_mounts}" ]; then
39 bind_mounts="${OPTARG}"
40 else
41 if [ "${bind_mounts}" = "NONE" -o "${OPTARG}" = "${OPTARG#/}" -o \
42 ! -d "${OPTARG}" ]; then
43 echo "Invalid -l option(s)"
Michael Moss 2012/03/15 17:35:37 typo: Invalid -b option(s)
Markus (顧孟勤) 2012/03/15 18:20:10 Thanks!
44 usage
45 exit 1
46 fi
47 bind_mounts="${bind_mounts}
48 ${OPTARG} ${OPTARG} none rw,bind 0 0"
49 fi
50 ;;
27 g) 51 g)
28 [ -n "${OPTARG}" ] && 52 [ -n "${OPTARG}" ] &&
29 chroot_groups="${chroot_groups}${chroot_groups:+,}${OPTARG}" 53 chroot_groups="${chroot_groups}${chroot_groups:+,}${OPTARG}"
30 ;; 54 ;;
55 l)
56 list_all_chroots
57 exit
58 ;;
31 m) 59 m)
32 if [ -n "${mirror}" ]; then 60 if [ -n "${mirror}" ]; then
33 echo "You can only specify exactly one mirror location" 61 echo "You can only specify exactly one mirror location"
34 usage 62 usage
35 exit 1 63 exit 1
36 fi 64 fi
37 mirror="$OPTARG" 65 mirror="$OPTARG"
38 ;; 66 ;;
39 s) 67 s)
40 add_srcs="y" 68 add_srcs="y"
(...skipping 18 matching lines...) Expand all
59 esac 87 esac
60 done 88 done
61 89
62 if [ $# -ge ${OPTIND} ]; then 90 if [ $# -ge ${OPTIND} ]; then
63 eval echo "Unexpected command line argument: \${${OPTIND}}" 91 eval echo "Unexpected command line argument: \${${OPTIND}}"
64 usage 92 usage
65 exit 1 93 exit 1
66 fi 94 fi
67 } 95 }
68 96
97 list_all_chroots() {
98 for i in /var/lib/chroot/*; do
99 i="${i##*/}"
100 [ "${i}" = "*" ] && continue
101 [ -x "/usr/local/bin/${i%bit}" ] || continue
102 grep "^\[${i%bit}\]\$" /etc/schroot/schroot.conf >&/dev/null || continue
Michael Moss 2012/03/15 17:35:37 nit: same thing with the -q
103 [ -r "/etc/schroot/script-${i}" -a \
104 -r "/etc/schroot/mount-${i}" ] || continue
105 echo "${i%bit}"
106 done
107 }
108
109 getkey() {
110 (
111 trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT HUP
112 stty -echo iuclc -icanon 2>/dev/null
113 dd count=1 bs=1 2>/dev/null
114 )
115 }
116
117 chr() {
118 printf "\\$(printf '%03o' "$1")"
119 }
120
121 ord() {
122 printf '%d' $(printf '%c' "$1" | od -tu1 -An)
123 }
124
125 is_network_drive() {
126 stat -c %T -f "$1/" 2>/dev/null |
127 egrep '^nfs|cifs|smbfs' >&/dev/null
128 }
69 129
70 # Check that we are running as a regular user 130 # Check that we are running as a regular user
71 [ "$(id -nu)" = root ] && { 131 [ "$(id -nu)" = root ] && {
72 echo "Run this script as a regular user and provide your \"sudo\"" \ 132 echo "Run this script as a regular user and provide your \"sudo\"" \
73 "password if requested" >&2 133 "password if requested" >&2
74 exit 1 134 exit 1
75 } 135 }
76 mkdir -p "$HOME/chroot/"
77 136
78 process_opts "$@" 137 process_opts "$@"
79 138
139 echo "This script will help you through the process of installing a"
140 echo "Debian or Ubuntu distribution in a chroot environment. You will"
141 echo "have to provide your \"sudo\" password when requested."
142 echo
143
80 # Error handler 144 # Error handler
81 trap 'exit 1' INT TERM QUIT 145 trap 'exit 1' INT TERM QUIT HUP
82 trap 'sudo apt-get clean; tput bel; echo; echo Failed' EXIT 146 trap 'sudo apt-get clean; tput bel; echo; echo Failed' EXIT
83 147
84 # Install any missing applications that this script relies on. If these packages 148 # Install any missing applications that this script relies on. If these packages
85 # are already installed, don't force another "apt-get install". That would 149 # are already installed, don't force another "apt-get install". That would
86 # prevent them from being auto-removed, if they ever become eligible for that. 150 # prevent them from being auto-removed, if they ever become eligible for that.
87 # And as this script only needs the packages once, there is no good reason to 151 # And as this script only needs the packages once, there is no good reason to
88 # introduce a hard dependency on things such as dchroot and debootstrap. 152 # introduce a hard dependency on things such as dchroot and debootstrap.
89 dep= 153 dep=
90 for i in dchroot debootstrap; do 154 for i in dchroot debootstrap libwww-perl; do
91 [ -d /usr/share/doc/"$i" ] || dep="$dep $i" 155 [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
92 done 156 done
93 [ -n "$dep" ] && sudo apt-get -y install $dep 157 [ -n "$dep" ] && sudo apt-get -y install $dep
94 sudo apt-get -y install schroot 158 sudo apt-get -y install schroot
95 159
96 # Create directory for chroot 160 # Create directory for chroot
97 sudo mkdir -p /var/lib/chroot 161 sudo mkdir -p /var/lib/chroot
98 162
99 # Find chroot environments that can be installed with debootstrap 163 # Find chroot environments that can be installed with debootstrap
100 targets="$(cd /usr/share/debootstrap/scripts 164 targets="$(cd /usr/share/debootstrap/scripts
101 ls | grep '^[a-z]*$')" 165 ls | grep '^[a-z]*$')"
102 166
103 # Ask user to pick one of the available targets 167 # Ask user to pick one of the available targets
104 echo "The following targets are available to be installed in a chroot:" 168 echo "The following targets are available to be installed in a chroot:"
105 j=1; for i in $targets; do 169 j=1; for i in $targets; do
106 printf '%4d: %s\n' "$j" "$i" 170 printf '%4d: %s\n' "$j" "$i"
107 j=$(($j+1)) 171 j=$(($j+1))
108 done 172 done
109 while :; do 173 while :; do
110 printf "Which target would you like to install: " 174 printf "Which target would you like to install: "
111 read n 175 read n
112 [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break 176 [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break
113 done 177 done
114 j=1; for i in $targets; do 178 j=1; for i in $targets; do
115 [ "$j" -eq "$n" ] && { distname="$i"; break; } 179 [ "$j" -eq "$n" ] && { distname="$i"; break; }
116 j=$(($j+1)) 180 j=$(($j+1))
117 done 181 done
182 echo
118 183
119 # On x86-64, ask whether the user wants to install x86-32 or x86-64 184 # On x86-64, ask whether the user wants to install x86-32 or x86-64
120 archflag= 185 archflag=
121 arch= 186 arch=
122 if [ "$(uname -m)" = x86_64 ]; then 187 if [ "$(uname -m)" = x86_64 ]; then
123 while :; do 188 while :; do
124 echo "You are running a 64bit kernel. This allows you to install either a" 189 echo "You are running a 64bit kernel. This allows you to install either a"
125 printf "32bit or a 64bit chroot environment. %s" \ 190 printf "32bit or a 64bit chroot environment. %s" \
126 "Which one do you want (32, 64) " 191 "Which one do you want (32, 64) "
127 read arch 192 read arch
128 [ "${arch}" == 32 -o "${arch}" == 64 ] && break 193 [ "${arch}" == 32 -o "${arch}" == 64 ] && break
129 done 194 done
130 [ "${arch}" == 32 ] && archflag="--arch i386" || archflag="--arch amd64" 195 [ "${arch}" == 32 ] && archflag="--arch i386" || archflag="--arch amd64"
131 arch="${arch}bit" 196 arch="${arch}bit"
197 echo
132 fi 198 fi
133 target="${distname}${arch}" 199 target="${distname}${arch}"
134 200
135 # Don't overwrite an existing installation 201 # Don't accidentally overwrite an existing installation
136 [ -d /var/lib/chroot/"${target}" ] && { 202 [ -d /var/lib/chroot/"${target}" ] && {
137 echo "This chroot already exists on your machine." >&2 203 while :; do
138 echo "Delete /var/lib/chroot/${target} if you want to start over." >&2 204 echo "This chroot already exists on your machine."
139 exit 1 205 if schroot -l --all-sessions 2>&1 |
206 sed 's/^session://' |
207 grep "^${target%bit}-" >&/dev/null; then
208 echo "And it appears to be in active use. Terminate all programs that"
209 echo "are currently using the chroot environment and then re-run this"
210 echo "script."
211 echo "If you still get an error message, you might have stale mounts"
212 echo "that you forgot to delete. You can always clean up mounts by"
213 echo "executing \"${target%bit} -c\"."
214 exit 1
215 fi
216 echo "I can abort installation, I can overwrite the existing chroot,"
217 echo "or I can delete the old one and then exit. What would you like to"
218 printf "do (a/o/d)? "
219 read choice
220 case "${choice}" in
221 a|A) exit 1;;
222 o|O) sudo rm -rf "/var/lib/chroot/${target}"; break;;
223 d|D) sudo rm -rf "/var/lib/chroot/${target}"; exit 0;;
224 esac
225 done
226 echo
140 } 227 }
141 sudo mkdir -p /var/lib/chroot/"${target}" 228 sudo mkdir -p /var/lib/chroot/"${target}"
142 229
143 # Offer to include additional standard repositories for Ubuntu-based chroots. 230 # Offer to include additional standard repositories for Ubuntu-based chroots.
144 alt_repos= 231 alt_repos=
145 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null && { 232 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null && {
146 while :; do 233 while :; do
147 echo "Would you like to add ${distname}-updates and ${distname}-security " 234 echo "Would you like to add ${distname}-updates and ${distname}-security "
148 echo -n "to the chroot's sources.list (y/n)? " 235 printf "to the chroot's sources.list (y/n)? "
149 read alt_repos 236 read alt_repos
150 case "${alt_repos}" in 237 case "${alt_repos}" in
151 y|Y) 238 y|Y)
152 alt_repos="y" 239 alt_repos="y"
153 break 240 break
154 ;; 241 ;;
155 n|N) 242 n|N)
156 break 243 break
157 ;; 244 ;;
158 esac 245 esac
159 done 246 done
247 echo
160 } 248 }
161 249
250 # Check for non-standard file system mount points and ask the user whether
251 # they should be imported into the chroot environment
252 if [ -z "${bind_mounts}" ]; then
253 mounts="$(awk '$2 != "/" && $2 !~ "^/boot" && $2 !~ "^/home" &&
254 $2 !~ "^/media" && $2 !~ "^/run" &&
255 ($3 ~ "ext[2-4]" || $3 == "reiserfs" || $3 == "btrfs" ||
256 $3 == "xfs" || $3 == "jfs" || $3 == "u?msdos" ||
257 $3 == "v?fat" || $3 == "hfs" || $3 == "ntfs" ||
258 $3 ~ "nfs[4-9]?" || $3 == "smbfs" || $3 == "cifs") {
259 print $2
260 }' /proc/mounts |
261 head -n26)"
Michael Moss 2012/03/15 17:35:37 Maybe add to the comment above that we limit it to
Markus (顧孟勤) 2012/03/15 18:20:10 Done
262 if [ -n "${mounts}" ]; then
263 echo "You appear to have non-standard mount points that you"
264 echo "might want to import into the chroot environment:"
265 echo
266 sel=
267 while :; do
268 # Print a menu, listing all non-default mounts of local or network
269 # file systems.
270 j=1; for m in ${mounts}; do
271 c="$(printf $(printf '\\%03o' $((64+$j))))"
272 echo "$sel" | grep $c >/dev/null &&
273 state="mounted in chroot" || state="$(tput el)"
274 printf " $c) %-40s${state}\n" "$m"
275 j=$(($j+1))
276 done
277 # Allow user to interactively (de-)select any of the entries
278 echo
279 printf "Select mount points that you want to be included or press %s" \
280 "SPACE to continue"
281 c="$(getkey | tr a-z A-Z)"
282 [ "$c" == " " ] && { echo; echo; break; }
283 if [ -z "$c" ] ||
284 [ "$c" '<' 'A' -o $(ord "$c") -gt $((64 + $(ord "$j"))) ]; then
285 # Invalid input, ring the console bell
286 tput bel
287 else
288 # Toggle the selection for the given entry
289 if echo "$sel" | grep $c >/dev/null; then
290 sel="$(printf "$sel" | sed "s/$c//")"
291 else
292 sel="$sel$c"
293 fi
294 fi
295 # Reposition cursor to the top of the list of entries
296 tput cuu $(($j + 1))
297 echo
298 done
299 fi
300 j=1; for m in ${mounts}; do
301 c="$(chr $(($j + 64)))"
302 if echo "$sel" | grep $c >/dev/null; then
303 bind_mounts="${bind_mounts}$m $m none rw,bind 0 0
304 "
305 fi
306 j=$(($j+1))
307 done
308 fi
309
162 # Remove stale entry from /etc/schroot/schroot.conf. Entries start 310 # Remove stale entry from /etc/schroot/schroot.conf. Entries start
163 # with the target name in square brackets, followed by an arbitrary 311 # with the target name in square brackets, followed by an arbitrary
164 # number of lines. The entry stops when either the end of file has 312 # number of lines. The entry stops when either the end of file has
165 # been reached, or when the beginning of a new target is encountered. 313 # been reached, or when the beginning of a new target is encountered.
166 # This means, we cannot easily match for a range of lines in 314 # This means, we cannot easily match for a range of lines in
167 # "sed". Instead, we actually have to iterate over each line and check 315 # "sed". Instead, we actually have to iterate over each line and check
168 # whether it is the beginning of a new entry. 316 # whether it is the beginning of a new entry.
169 sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p' \ 317 sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
170 /etc/schroot/schroot.conf 318 /etc/schroot/schroot.conf
171 319
172 # Download base system. This takes some time 320 # Download base system. This takes some time
173 if [ -z "${mirror}" ]; then 321 if [ -z "${mirror}" ]; then
174 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null && 322 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null &&
175 mirror="http://archive.ubuntu.com/ubuntu" || 323 mirror="http://archive.ubuntu.com/ubuntu" ||
176 mirror="http://ftp.us.debian.org/debian" 324 mirror="http://ftp.us.debian.org/debian"
177 fi 325 fi
178 sudo debootstrap ${archflag} "${distname}" /var/lib/chroot/"${target}" \ 326 sudo debootstrap ${archflag} "${distname}" /var/lib/chroot/"${target}" \
179 "$mirror" 327 "$mirror"
180 328
181 # Add new entry to /etc/schroot/schroot.conf 329 # Add new entry to /etc/schroot/schroot.conf
182 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null && 330 grep ubuntu.com /usr/share/debootstrap/scripts/"${distname}" >&/dev/null &&
183 brand="Ubuntu" || brand="Debian" 331 brand="Ubuntu" || brand="Debian"
184 if [ -z "${chroot_groups}" ]; then 332 if [ -z "${chroot_groups}" ]; then
185 chroot_groups="admin,$(id -gn)" 333 chroot_groups="${admin},$(id -gn)"
186 fi 334 fi
335 # Older versions of schroot wanted a "priority=" line, whereas recent
336 # versions deprecate "priority=" and warn if they see it. We don't have
337 # a good feature test, but scanning for the string "priority=" in the
338 # existing "schroot.conf" file is a good indication of what to do.
339 priority=$(grep 'priority=' /etc/schroot/schroot.conf >&/dev/null &&
340 echo 'priority=3' || :)
187 sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF 341 sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
188 [${target%bit}] 342 [${target%bit}]
189 description=${brand} ${distname} ${arch} 343 description=${brand} ${distname} ${arch}
190 type=directory 344 type=directory
191 directory=/var/lib/chroot/${target} 345 directory=/var/lib/chroot/${target}
192 priority=3
193 users=root 346 users=root
194 groups=${chroot_groups} 347 groups=${chroot_groups}
195 root-groups=${chroot_groups} 348 root-groups=${chroot_groups}
196 personality=linux$([ "${arch}" != 64bit ] && echo 32) 349 personality=linux$([ "${arch}" != 64bit ] && echo 32)
197 script-config=script-${target} 350 script-config=script-${target}
351 ${priority}
198 352
199 EOF 353 EOF
200 354
201 # Set up a special directory that changes contents depending on the target 355 # Set up a list of mount points that is specific to this
202 # that is executing. 356 # chroot environment.
203 sed '/^FSTAB=/s,/mount-defaults",/mount-'"${target}"'",' \ 357 sed '/^FSTAB=/s,"[^"]*","/etc/schroot/mount-'"${target}"'",' \
204 /etc/schroot/script-defaults | 358 /etc/schroot/script-defaults |
205 sudo sh -c 'cat >/etc/schroot/script-'"${target}" 359 sudo sh -c 'cat >/etc/schroot/script-'"${target}"
206 sed '\,^/home[/[:space:]],s/\([,[:space:]]\)bind[[:space:]]/\1rbind /' \ 360 sed '\,^/home[/[:space:]],s/\([,[:space:]]\)bind[[:space:]]/\1rbind /' \
207 /etc/schroot/mount-defaults | 361 /etc/schroot/mount-defaults |
208 sudo sh -c 'cat > /etc/schroot/mount-'"${target}" 362 sudo sh -c 'cat > /etc/schroot/mount-'"${target}"
209 echo "$HOME/chroot/.${target} $HOME/chroot none rw,bind 0 0" | 363
364 # Add the extra mount points that the user told us about
365 [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
366 printf "${bind_mounts}" |
367 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
368
369 # If this system has a "/media" mountpoint, import it into the chroot
370 # environment. Most modern distributions use this mount point to
371 # automatically mount devices such as CDROMs, USB sticks, etc...
372 if [ -d /media ] &&
373 ! grep '^/media' /etc/schroot/mount-"${target}" >&/dev/null; then
374 echo '/media /media none rw,bind 0 0' |
Michael Moss 2012/03/15 17:35:37 This should probably be rbind, since these things
Markus (顧孟勤) 2012/03/15 18:20:10 Very good call :-) Yes, that would never have work
375 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
376 fi
377
378 # Share /dev/shm and possibly /run/shm
379 grep '^/dev/shm' /etc/schroot/mount-"${target}" >&/dev/null ||
380 echo '/dev/shm /dev/shm none rw,bind 0 0' |
381 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
382 if [ -d "/var/lib/chroot/${target}/run" ] &&
383 ! grep '^/run/shm' /etc/schroot/mount-"${target}" >&/dev/null; then
384 { [ -d /run ] && echo '/run/shm /run/shm none rw,bind 0 0' ||
385 echo '/dev/shm /run/shm none rw,bind 0 0'; } |
386 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
387 fi
388
389 # Set up a special directory that changes contents depending on the target
390 # that is executing.
391 d="$(readlink -f "${HOME}/chroot" 2>/dev/null || echo "${HOME}/chroot")"
392 s="${d}/.${target}"
393 echo "${s} ${d} none rw,bind 0 0" |
210 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}" 394 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
211 mkdir -p "$HOME/chroot/.${target}" 395 mkdir -p "${s}"
212 396
213 # Install a helper script to launch commands in the chroot 397 # Install a helper script to launch commands in the chroot
214 sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<EOF 398 sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<'EOF'
215 #!/bin/bash 399 #!/bin/bash
216 if [ \$# -eq 0 ]; then 400
217 exec schroot -c ${target%bit} -p 401 chroot="${0##*/}"
402
403 wrap() {
404 # Word-wrap the text passed-in on stdin. Optionally, on continuation lines
405 # insert the same number of spaces as the number of characters in the
406 # parameter(s) passed to this function.
407 # If the "fold" program cannot be found, or if the actual width of the
408 # terminal cannot be determined, this function doesn't attempt to do any
409 # wrapping.
410 local f="$(type -P fold)"
411 [ -z "${f}" ] && { cat; return; }
412 local c="$(stty -a </dev/tty 2>/dev/null |
413 sed 's/.*columns[[:space:]]*\([0-9]*\).*/\1/;t;d')"
414 [ -z "${c}" ] && { cat; return; }
415 local i="$(echo "$*"|sed 's/./ /g')"
416 local j="$(printf %s "${i}"|wc -c)"
417 if [ "${c}" -gt "${j}" ]; then
418 dd bs=1 count="${j}" 2>/dev/null
419 "${f}" -sw "$((${c}-${j}))" | sed '2,$s/^/'"${i}"'/'
420 else
421 "${f}" -sw "${c}"
422 fi
423 }
424
425 help() {
426 echo "Usage ${0##*/} [-h|--help] [-c|--clean] [-C|--clean-all] [-l|--list] [-- ] args" | wrap "Usage ${0##*/} "
427 echo " help: print this message" | wrap " "
428 echo " list: list all known chroot environments" | wrap " "
429 echo " clean: remove all old chroot sessions for \"${chroot}\"" | wrap " "
430 echo " clean-all: remove all old chroot sessions for all environments" | wrap " "
431 exit 0
432 }
433
434 clean() {
435 local s t rc
436 rc=0
437 for s in $(schroot -l --all-sessions); do
438 if [ -n "$1" ]; then
439 t="${s#session:}"
440 [ "${t#${chroot}-}" == "${t}" ] && continue
441 fi
442 if ls -l /proc/*/{cwd,fd} 2>/dev/null |
443 fgrep -q "/var/lib/schroot/mount/${t}"; then
444 echo "Session \"${t}\" still has active users, not cleaning up" | wrap
445 rc=1
446 continue
447 fi
448 schroot -c "${s}" -e || rc=1
449 done
450 exit ${rc}
451 }
452
453 list() {
454 for e in $(schroot -l); do
455 e="${e#chroot:}"
456 [ -x "/usr/local/bin/${e}" ] || continue
457 if schroot -l --all-sessions 2>/dev/null |
458 sed 's/^session://' |
459 grep "^${e}-" >&/dev/null; then
460 echo "${e} is currently active"
461 else
462 echo "${e}"
463 fi
464 done
465 exit 0
466 }
467
468 while [ "$#" -ne 0 ]; do
469 case "$1" in
470 --) shift; break;;
471 -h|--help) shift; help;;
472 -l|--list) shift; list;;
473 -c|--clean) shift; clean "${chroot}";;
474 -C|--clean-all) shift; clean;;
475 *) break;;
476 esac
477 done
478
479 session="$(schroot -c "${chroot}" -b)"
480
481 if [ $# -eq 0 ]; then
482 schroot -c "${session}" -r -p
218 else 483 else
219 p="\$1"; shift 484 p="$1"; shift
220 exec schroot -c ${target%bit} -p "\$p" -- "\$@" 485 schroot -c "${session}" -r -p "$p" -- "$@"
221 fi 486 fi
222 exit 1 487 rc=$?
488
489 i=$(schroot -c "${session}" -r -p ls -- -id /proc/self/root/. |
490 awk '{ print $1 }') 2>/dev/null
491 while [ -n "$i" ]; do
492 pids=$(ls -id1 /proc/*/root/. 2>/dev/null |
493 sed -e 's,^[^0-9]*'$i'.*/\([1-9][0-9]*\)/.*$,\1,
494 t
495 d') >/dev/null 2>&1
496 [ -z "$pids" ] && break
497 kill -9 $pids
498 done
499 schroot -c "${session}" -e
500 exit $rc
223 EOF 501 EOF
224 sudo chown root:root /usr/local/bin/"${target%bit}" 502 sudo chown root:root /usr/local/bin/"${target%bit}"
225 sudo chmod 755 /usr/local/bin/"${target%bit}" 503 sudo chmod 755 /usr/local/bin/"${target%bit}"
226 504
227 # Add the standard Ubuntu update repositories if requested. 505 # Add the standard Ubuntu update repositories if requested.
228 [ "${alt_repos}" = "y" -a \ 506 [ "${alt_repos}" = "y" -a \
229 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && 507 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
230 sudo sed -i '/^deb .* [^ -]\+ main$/p 508 sudo sed -i '/^deb .* [^ -]\+ main$/p
231 s/^\(deb .* [^ -]\+\) main/\1-security main/ 509 s/^\(deb .* [^ -]\+\) main/\1-security main/
232 p 510 p
233 t1 511 t1
234 d 512 d
235 :1;s/-security main/-updates main/ 513 :1;s/-security main/-updates main/
236 t 514 t
237 d' "/var/lib/chroot/${target}/etc/apt/sources.list" 515 d' "/var/lib/chroot/${target}/etc/apt/sources.list"
238 516
239 # Add a few more repositories to the chroot 517 # Add a few more repositories to the chroot
518 [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
519 sudo sed -i 's/ main$/ main restricted universe multiverse/' \
520 "/var/lib/chroot/${target}/etc/apt/sources.list"
521
522 # Add the Ubuntu "partner" repository, if available
523 if [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
524 HEAD "http://archive.canonical.com/ubuntu/dists/${distname}/partner" \
525 >&/dev/null; then
526 sudo sh -c '
527 echo "deb http://archive.canonical.com/ubuntu" \
528 "'"${distname}"' partner" \
529 >>"/var/lib/chroot/'"${target}"'/etc/apt/sources.list"'
530 fi
531
532 # Add source repositories, if the user requested we do so
240 [ "${add_srcs}" = "y" -a \ 533 [ "${add_srcs}" = "y" -a \
241 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && 534 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
242 sudo sed -i 's/ main$/ main restricted universe multiverse/ 535 sudo sed -i '/^deb[^-]/p
243 p 536 s/^deb\([^-]\)/deb-src\1/' \
244 t1 537 "/var/lib/chroot/${target}/etc/apt/sources.list"
245 d
246 :1;s/^deb/deb-src/
247 t
248 d' "/var/lib/chroot/${target}/etc/apt/sources.list"
249 538
250 # Update packages 539 # Update packages
251 sudo schroot -c "${target%bit}" -p -- /bin/sh -c ' 540 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
252 apt-get update; apt-get -y dist-upgrade' || : 541 apt-get update; apt-get -y dist-upgrade' || :
253 542
254 # Install a couple of missing packages 543 # Install a couple of missing packages
255 for i in debian-keyring ubuntu-keyring locales sudo; do 544 for i in debian-keyring ubuntu-keyring locales sudo; do
256 [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] || 545 [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
257 sudo schroot -c "${target%bit}" -p -- apt-get -y install "$i" || : 546 sudo "/usr/local/bin/${target%bit}" apt-get -y install "$i" || :
258 done 547 done
259 548
260 # Configure locales 549 # Configure locales
261 sudo schroot -c "${target%bit}" -p -- /bin/sh -c ' 550 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
262 l='"${LANG:-en_US}"'; l="${l%%.*}" 551 l='"${LANG:-en_US}"'; l="${l%%.*}"
263 [ -r /etc/locale.gen ] && 552 [ -r /etc/locale.gen ] &&
264 sed -i "s/^# \($l\)/\1/" /etc/locale.gen 553 sed -i "s/^# \($l\)/\1/" /etc/locale.gen
265 locale-gen $LANG en_US en_US.UTF-8' || : 554 locale-gen $LANG en_US en_US.UTF-8' || :
266 555
556 # Enable multi-arch support, if available
557 sudo "/usr/local/bin/${target%bit}" dpkg --assert-multi-arch >&/dev/null &&
558 [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && {
559 sudo sed -i 's/ / [arch=amd64,i386] /' \
560 "/var/lib/chroot/${target}/etc/apt/sources.list"
561 [ -d /var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/ ] &&
562 echo foreign-architecture \
563 $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) |
564 sudo sh -c "cat >'/var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/multiarch'"
565 }
566
267 # Configure "sudo" package 567 # Configure "sudo" package
268 sudo schroot -c "${target%bit}" -p -- /bin/sh -c ' 568 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
269 egrep '"'^$(id -nu) '"' /etc/sudoers >/dev/null 2>&1 || 569 egrep '"'^$(id -nu) '"' /etc/sudoers >/dev/null 2>&1 ||
270 echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers' 570 echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'
271 571
272 # Install a few more commonly used packages 572 # Install a few more commonly used packages
273 sudo schroot -c "${target%bit}" -p -- apt-get -y install \ 573 sudo "/usr/local/bin/${target%bit}" apt-get -y install \
274 autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool \ 574 autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool \
275 strace 575 strace
276 576
277 # If running a 32bit environment on a 64bit machine, install a few binaries 577 # If running a 32bit environment on a 64bit machine, install a few binaries
278 # as 64bit. This is only done automatically if the chroot distro is the same as 578 # as 64bit. This is only done automatically if the chroot distro is the same as
279 # the host, otherwise there might be incompatibilities in build settings or 579 # the host, otherwise there might be incompatibilities in build settings or
280 # runtime dependencies. The user can force it with the '-c' flag. 580 # runtime dependencies. The user can force it with the '-c' flag.
281 host_distro=$(grep DISTRIB_CODENAME /etc/lsb-release 2>/dev/null | \ 581 host_distro=$(grep DISTRIB_CODENAME /etc/lsb-release 2>/dev/null | \
282 cut -d "=" -f 2) 582 cut -d "=" -f 2)
283 if [ "${copy_64}" = "y" -o \ 583 if [ "${copy_64}" = "y" -o \
284 "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \ 584 "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \
285 file /bin/bash 2>/dev/null | grep -q x86-64; then 585 file /bin/bash 2>/dev/null | grep -q x86-64; then
286 readlinepkg=$(sudo schroot -c "${target%bit}" -p -- sh -c \ 586 readlinepkg=$(sudo "/usr/local/bin/${target%bit}" sh -c \
287 'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1') 587 'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1')
288 sudo schroot -c "${target%bit}" -p -- apt-get -y install \ 588 sudo "/usr/local/bin/${target%bit}" apt-get -y install \
289 lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1 589 lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1
290 dep= 590 dep=
291 for i in binutils gdb strace; do 591 for i in binutils gdb; do
292 [ -d /usr/share/doc/"$i" ] || dep="$dep $i" 592 [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
293 done 593 done
294 [ -n "$dep" ] && sudo apt-get -y install $dep 594 [ -n "$dep" ] && sudo apt-get -y install $dep
295 sudo cp /usr/bin/gdb "/var/lib/chroot/${target}/usr/local/bin/" 595 sudo mkdir -p "/var/lib/chroot/${target}/usr/local/lib/amd64"
296 sudo cp /usr/bin/ld "/var/lib/chroot/${target}/usr/local/bin/"
297 for i in libbfd libpython; do 596 for i in libbfd libpython; do
298 lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } | 597 lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
299 grep "$i" | awk '{ print $3 }')" 598 grep "$i" | awk '{ print $3 }')"
300 if [ -n "$lib" -a -r "$lib" ]; then 599 if [ -n "$lib" -a -r "$lib" ]; then
301 sudo cp "$lib" "/var/lib/chroot/${target}/usr/lib64/" 600 sudo cp "$lib" "/var/lib/chroot/${target}/usr/local/lib/amd64"
302 fi 601 fi
303 done 602 done
304 for lib in libssl libcrypt; do 603 for lib in libssl libcrypt; do
305 sudo cp /usr/lib/$lib* "/var/lib/chroot/${target}/usr/lib64/" || : 604 for path in /usr/lib /usr/lib/x86_64-linux-gnu; do
605 sudo cp $path/$lib* \
606 "/var/lib/chroot/${target}/usr/local/lib/amd64/" >&/dev/null || :
607 done
608 done
609 for i in gdb ld; do
610 sudo cp /usr/bin/$i "/var/lib/chroot/${target}/usr/local/lib/amd64/"
611 sudo sh -c "cat >'/var/lib/chroot/${target}/usr/local/bin/$i'" <<EOF
612 #!/bin/sh
613 exec /lib64/ld-linux-x86-64.so.2 --library-path /usr/local/lib/amd64 \
614 /usr/local/lib/amd64/$i "\$@"
615 EOF
616 sudo chmod 755 "/var/lib/chroot/${target}/usr/local/bin/$i"
617 done
618 fi
619
620
621 # If the install-build-deps.sh script can be found, offer to run it now
622 script="$(dirname $(readlink -f "$0"))/install-build-deps.sh"
623 if [ -x "${script}" ]; then
624 while :; do
625 echo
626 echo "If you plan on building Chrome inside of the new chroot environment,"
627 echo "you now have to install the build dependencies. Do you want me to"
628 printf "start the script that does this for you (y/n)? "
629 read install_deps
630 case "${install_deps}" in
631 y|Y)
632 echo
633 # We prefer running the script in-place, but this might not be
634 # possible, if it lives on a network filesystem that denies
635 # access to root.
636 tmp_script=
637 if ! sudo "${target%bit}" sh -c "[ -x '${script}' ]" >&/dev/null; then
638 tmp_script="/tmp/${script##*/}"
639 cp "${script}" "${tmp_script}"
640 fi
641 # Some distributions automatically start an instance of the system-
642 # wide dbus daemon, when installing the Chrome build depencies. This
643 # prevents the chroot session from being closed. So, we always try
644 # to shut down any running instance of dbus.
645 sudo "${target%bit}" sh -c "${script} --no-lib32;
646 rc=$?;
647 /etc/init.d/dbus stop >/dev/null 2>&1 || :;
648 exit $rc"
649 rc=$?
650 [ -n "${tmp_script}" ] && rm -f "${tmp_script}"
651 [ $rc -ne 0 ] && exit $rc
652 break
653 ;;
654 n|N)
655 break
656 ;;
657 esac
658 done
659 echo
660 fi
661
662 # Check whether ~/chroot is on a (slow) network file system and offer to
663 # relocate it. Also offer relocation, if the user appears to have multiple
664 # spindles (as indicated by "${bind_mount}" being non-empty).
665 # We only offer this option, if it doesn't look as if a chroot environment
666 # is currently active. Otherwise, relocation is unlikely to work and it
667 # can be difficult for the user to recover from the failed attempt to relocate
668 # the ~/chroot directory.
669 # We don't aim to solve this problem for every configuration,
670 # but try to help with the common cases. For more advanced configuration
671 # options, the user can always manually adjust things.
672 mkdir -p "${HOME}/chroot/"
673 if [ ! -h "${HOME}/chroot" ] &&
674 ! egrep '^[^[:space:]]*/chroot' /etc/fstab >&/dev/null &&
675 { [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] ||
676 is_network_drive "${HOME}/chroot"; } &&
677 ! egrep '/var/lib/[^/]*chroot/.*/chroot' /proc/mounts >&/dev/null; then
678 echo "${HOME}/chroot is currently located on the same device as your"
679 echo "home directory."
680 echo "This might not be what you want. Do you want me to move it somewhere"
681 echo "else?"
682 # If the computer has multiple spindles, many users configure all or part of
683 # the secondary hard disk to be writable by the primary user of this machine.
684 # Make some reasonable effort to detect this type of configuration and
685 # then offer a good location for where to put the ~/chroot directory.
686 suggest=
687 for i in $(echo "${bind_mounts}"|cut -d ' ' -f 1); do
688 if [ -d "$i" -a -w "$i" -a \( ! -a "$i/chroot" -o -w "$i/chroot/." \) ] &&
689 ! is_network_drive "$i"; then
690 suggest="$i"
691 else
692 for j in "$i/"*; do
693 if [ -d "$j" -a -w "$j" -a \
694 \( ! -a "$j/chroot" -o -w "$j/chroot/." \) ] &&
695 ! is_network_drive "$j"; then
696 suggest="$j"
697 else
698 for k in "$j/"*; do
699 if [ -d "$k" -a -w "$k" -a \
700 \( ! -a "$k/chroot" -o -w "$k/chroot/." \) ] &&
701 ! is_network_drive "$k"; then
702 suggest="$k"
703 break
704 fi
705 done
706 fi
707 [ -n "${suggest}" ] && break
708 done
709 fi
710 [ -n "${suggest}" ] && break
711 done
712 def_suggest="${HOME}"
713 if [ -n "${suggest}" ]; then
714 # For home directories that reside on network drives, make our suggestion
715 # the default option. For home directories that reside on a local drive,
716 # require that the user manually enters the new location.
717 if is_network_drive "${HOME}"; then
718 def_suggest="${suggest}"
719 else
720 echo "A good location would probably be in \"${suggest}\""
721 fi
722 fi
723 while :; do
724 printf "Physical location [${def_suggest}]: "
725 read dir
726 [ -z "${dir}" ] && dir="${def_suggest}"
727 [ "${dir%%/}" == "${HOME%%/}" ] && break
728 if ! [ -d "${dir}" -a -w "${dir}" ] ||
729 [ -a "${dir}/chroot" -a ! -w "${dir}/chroot/." ]; then
730 echo "Cannot write to ${dir}/chroot. Please try again"
731 else
732 mv "${HOME}/chroot" "${dir}/chroot"
733 ln -s "${dir}/chroot" "${HOME}/chroot"
734 for i in $(list_all_chroots); do
735 sudo "$i" mkdir -p "${dir}/chroot"
736 done
737 sudo sed -i "s,${HOME}/chroot,${dir}/chroot,g" /etc/schroot/mount-*
738 break
739 fi
306 done 740 done
307 fi 741 fi
308 742
309 # Clean up package files 743 # Clean up package files
310 sudo schroot -c "${target%bit}" -p -- apt-get clean 744 sudo schroot -c "${target%bit}" -p -- apt-get clean
311 sudo apt-get clean 745 sudo apt-get clean
312 746
747 trap '' INT TERM QUIT HUP
748 trap '' EXIT
749
313 # Let the user know what we did 750 # Let the user know what we did
314 trap '' INT TERM QUIT
315 trap '' EXIT
316 cat <<EOF 751 cat <<EOF
317 752
318 753
319 Successfully installed ${distname} ${arch} 754 Successfully installed ${distname} ${arch}
320 755
321 You can run programs inside of the chroot by invoking the "${target%bit}" 756 You can run programs inside of the chroot by invoking the "${target%bit}"
322 command. 757 command.
323 758
324 Your home directory is shared between the host and the chroot. But I configured 759 This command can be used with arguments, in order to just run a single
325 $HOME/chroot to be private to the chroot environment. You can use it 760 program inside of the chroot environment (e.g. "${target%bit} make chrome")
326 for files that need to differ between environments. 761 or without arguments, in order to run an interactive shell session inside
762 of the chroot environment.
763
764 If you need to run things as "root", you can use "sudo" (e.g. try
765 "sudo ${target%bit} apt-get update").
766
767 Your home directory is shared between the host and the chroot. But I
768 configured "${HOME}/chroot" to be private to the chroot environment.
769 You can use it for files that need to differ between environments. This
770 would be a good place to store binaries that you have built from your
771 source files.
772
773 For Chrome, this probably means you want to make your "out" directory a
774 symbolic link that points somewhere inside of "${HOME}/chroot".
775
776 You still need to run "gclient runhooks" whenever you switch from building
777 outside of the chroot to inside of the chroot. But you will find that you
778 don't have to repeatedly erase and then completely rebuild all your object
779 and binary files.
780
327 EOF 781 EOF
OLDNEW
« no previous file with comments | « build/install-build-deps.sh ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698