blob: e2d558b76c4b3dd4fe1005fcafcee025d980bf32 [file] [log] [blame]
[email protected]47b16752010-08-31 05:01:151#!/bin/bash -e
2
[email protected]b24c3dc2012-02-29 22:08:463# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]47b16752010-08-31 05:01:154# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
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
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
11# Debian-derived system.
12
[email protected]757c2962012-03-15 19:05:1813# Older Debian based systems had both "admin" and "adm" groups, with "admin"
14# apparently being used in more places. Newer distributions have standardized
[email protected]d4da57be2014-07-16 17:53:2015# on just the "adm" group. Check /etc/group for the preferred name of the
[email protected]757c2962012-03-15 19:05:1816# administrator group.
17admin=$(grep '^admin:' /etc/group >&/dev/null && echo admin || echo adm)
18
[email protected]04aea5a2010-10-15 00:40:3919usage() {
[email protected]8eb22e92010-10-20 03:32:1720 echo "usage: ${0##*/} [-m mirror] [-g group,...] [-s] [-c]"
[email protected]757c2962012-03-15 19:05:1821 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"
[email protected]6a617002010-10-15 20:56:2224 echo "-g group,... groups that can use the chroot unauthenticated"
[email protected]757c2962012-03-15 19:05:1825 echo " Default: '${admin}' and current user's group ('$(id -gn)')"
26 echo "-l List all installed chroot environments"
[email protected]6a617002010-10-15 20:56:2227 echo "-m mirror an alternate repository mirror for package downloads"
[email protected]8eb22e92010-10-20 03:32:1728 echo "-s configure default deb-srcs"
29 echo "-c always copy 64bit helper binaries to 32bit chroot"
[email protected]6a617002010-10-15 20:56:2230 echo "-h this help message"
[email protected]04aea5a2010-10-15 00:40:3931}
32
33process_opts() {
34 local OPTNAME OPTIND OPTERR OPTARG
[email protected]757c2962012-03-15 19:05:1835 while getopts ":b:g:lm:sch" OPTNAME; do
[email protected]04aea5a2010-10-15 00:40:3936 case "$OPTNAME" in
[email protected]757c2962012-03-15 19:05:1837 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 -b option(s)"
44 usage
45 exit 1
46 fi
47 bind_mounts="${bind_mounts}
48${OPTARG} ${OPTARG} none rw,bind 0 0"
49 fi
50 ;;
[email protected]6a617002010-10-15 20:56:2251 g)
52 [ -n "${OPTARG}" ] &&
53 chroot_groups="${chroot_groups}${chroot_groups:+,}${OPTARG}"
54 ;;
[email protected]757c2962012-03-15 19:05:1855 l)
56 list_all_chroots
57 exit
58 ;;
[email protected]04aea5a2010-10-15 00:40:3959 m)
60 if [ -n "${mirror}" ]; then
61 echo "You can only specify exactly one mirror location"
62 usage
63 exit 1
64 fi
65 mirror="$OPTARG"
66 ;;
[email protected]8eb22e92010-10-20 03:32:1767 s)
68 add_srcs="y"
69 ;;
70 c)
71 copy_64="y"
72 ;;
[email protected]04aea5a2010-10-15 00:40:3973 h)
74 usage
75 exit 0
76 ;;
77 \:)
78 echo "'-$OPTARG' needs an argument."
79 usage
80 exit 1
81 ;;
82 *)
83 echo "invalid command-line option: $OPTARG"
84 usage
85 exit 1
86 ;;
87 esac
88 done
89
90 if [ $# -ge ${OPTIND} ]; then
91 eval echo "Unexpected command line argument: \${${OPTIND}}"
92 usage
93 exit 1
94 fi
95}
96
[email protected]757c2962012-03-15 19:05:1897list_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 -qs "^\[${i%bit}\]\$" /etc/schroot/schroot.conf || continue
103 [ -r "/etc/schroot/script-${i}" -a \
104 -r "/etc/schroot/mount-${i}" ] || continue
105 echo "${i%bit}"
106 done
107}
108
109getkey() {
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
117chr() {
118 printf "\\$(printf '%03o' "$1")"
119}
120
121ord() {
122 printf '%d' $(printf '%c' "$1" | od -tu1 -An)
123}
124
125is_network_drive() {
126 stat -c %T -f "$1/" 2>/dev/null |
127 egrep -qs '^nfs|cifs|smbfs'
128}
[email protected]04aea5a2010-10-15 00:40:39129
[email protected]47b16752010-08-31 05:01:15130# Check that we are running as a regular user
131[ "$(id -nu)" = root ] && {
132 echo "Run this script as a regular user and provide your \"sudo\"" \
133 "password if requested" >&2
134 exit 1
135}
[email protected]47b16752010-08-31 05:01:15136
[email protected]04aea5a2010-10-15 00:40:39137process_opts "$@"
138
[email protected]757c2962012-03-15 19:05:18139echo "This script will help you through the process of installing a"
140echo "Debian or Ubuntu distribution in a chroot environment. You will"
141echo "have to provide your \"sudo\" password when requested."
142echo
143
[email protected]47b16752010-08-31 05:01:15144# Error handler
[email protected]757c2962012-03-15 19:05:18145trap 'exit 1' INT TERM QUIT HUP
[email protected]47b16752010-08-31 05:01:15146trap 'sudo apt-get clean; tput bel; echo; echo Failed' EXIT
147
148# Install any missing applications that this script relies on. If these packages
149# are already installed, don't force another "apt-get install". That would
150# prevent them from being auto-removed, if they ever become eligible for that.
151# And as this script only needs the packages once, there is no good reason to
152# introduce a hard dependency on things such as dchroot and debootstrap.
153dep=
[email protected]757c2962012-03-15 19:05:18154for i in dchroot debootstrap libwww-perl; do
[email protected]47b16752010-08-31 05:01:15155 [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
156done
157[ -n "$dep" ] && sudo apt-get -y install $dep
158sudo apt-get -y install schroot
159
160# Create directory for chroot
161sudo mkdir -p /var/lib/chroot
162
163# Find chroot environments that can be installed with debootstrap
164targets="$(cd /usr/share/debootstrap/scripts
165 ls | grep '^[a-z]*$')"
166
167# Ask user to pick one of the available targets
168echo "The following targets are available to be installed in a chroot:"
169j=1; for i in $targets; do
170 printf '%4d: %s\n' "$j" "$i"
171 j=$(($j+1))
172done
173while :; do
174 printf "Which target would you like to install: "
175 read n
176 [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break
177done
178j=1; for i in $targets; do
179 [ "$j" -eq "$n" ] && { distname="$i"; break; }
180 j=$(($j+1))
181done
[email protected]757c2962012-03-15 19:05:18182echo
[email protected]47b16752010-08-31 05:01:15183
184# On x86-64, ask whether the user wants to install x86-32 or x86-64
185archflag=
186arch=
187if [ "$(uname -m)" = x86_64 ]; then
188 while :; do
189 echo "You are running a 64bit kernel. This allows you to install either a"
190 printf "32bit or a 64bit chroot environment. %s" \
191 "Which one do you want (32, 64) "
192 read arch
193 [ "${arch}" == 32 -o "${arch}" == 64 ] && break
194 done
195 [ "${arch}" == 32 ] && archflag="--arch i386" || archflag="--arch amd64"
196 arch="${arch}bit"
[email protected]757c2962012-03-15 19:05:18197 echo
[email protected]47b16752010-08-31 05:01:15198fi
199target="${distname}${arch}"
200
[email protected]757c2962012-03-15 19:05:18201# Don't accidentally overwrite an existing installation
[email protected]47b16752010-08-31 05:01:15202[ -d /var/lib/chroot/"${target}" ] && {
[email protected]757c2962012-03-15 19:05:18203 while :; do
204 echo "This chroot already exists on your machine."
205 if schroot -l --all-sessions 2>&1 |
206 sed 's/^session://' |
207 grep -qs "^${target%bit}-"; 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;;
[email protected]b11411c2012-03-21 22:09:41223 d|D) sudo rm -rf "/var/lib/chroot/${target}" \
224 "/usr/local/bin/${target%bit}" \
225 "/etc/schroot/mount-${target}" \
226 "/etc/schroot/script-${target}"
227 sudo sed -ni '/^[[]'"${target%bit}"']$/,${
228 :1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
229 "/etc/schroot/schroot.conf"
230 trap '' INT TERM QUIT HUP
231 trap '' EXIT
232 echo "Deleted!"
233 exit 0;;
[email protected]757c2962012-03-15 19:05:18234 esac
235 done
236 echo
[email protected]47b16752010-08-31 05:01:15237}
238sudo mkdir -p /var/lib/chroot/"${target}"
239
[email protected]04aea5a2010-10-15 00:40:39240# Offer to include additional standard repositories for Ubuntu-based chroots.
241alt_repos=
[email protected]757c2962012-03-15 19:05:18242grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" && {
[email protected]04aea5a2010-10-15 00:40:39243 while :; do
244 echo "Would you like to add ${distname}-updates and ${distname}-security "
[email protected]757c2962012-03-15 19:05:18245 printf "to the chroot's sources.list (y/n)? "
[email protected]04aea5a2010-10-15 00:40:39246 read alt_repos
247 case "${alt_repos}" in
248 y|Y)
249 alt_repos="y"
250 break
251 ;;
252 n|N)
253 break
254 ;;
255 esac
256 done
[email protected]757c2962012-03-15 19:05:18257 echo
[email protected]04aea5a2010-10-15 00:40:39258}
259
[email protected]757c2962012-03-15 19:05:18260# Check for non-standard file system mount points and ask the user whether
261# they should be imported into the chroot environment
262# We limit to the first 26 mount points that much some basic heuristics,
263# because a) that allows us to enumerate choices with a single character,
264# and b) if we find more than 26 mount points, then these are probably
265# false-positives and something is very unusual about the system's
266# configuration. No need to spam the user with even more information that
267# is likely completely irrelevant.
268if [ -z "${bind_mounts}" ]; then
269 mounts="$(awk '$2 != "/" && $2 !~ "^/boot" && $2 !~ "^/home" &&
270 $2 !~ "^/media" && $2 !~ "^/run" &&
271 ($3 ~ "ext[2-4]" || $3 == "reiserfs" || $3 == "btrfs" ||
272 $3 == "xfs" || $3 == "jfs" || $3 == "u?msdos" ||
273 $3 == "v?fat" || $3 == "hfs" || $3 == "ntfs" ||
274 $3 ~ "nfs[4-9]?" || $3 == "smbfs" || $3 == "cifs") {
275 print $2
276 }' /proc/mounts |
277 head -n26)"
278 if [ -n "${mounts}" ]; then
279 echo "You appear to have non-standard mount points that you"
280 echo "might want to import into the chroot environment:"
281 echo
282 sel=
283 while :; do
284 # Print a menu, listing all non-default mounts of local or network
285 # file systems.
286 j=1; for m in ${mounts}; do
287 c="$(printf $(printf '\\%03o' $((64+$j))))"
288 echo "$sel" | grep -qs $c &&
289 state="mounted in chroot" || state="$(tput el)"
290 printf " $c) %-40s${state}\n" "$m"
291 j=$(($j+1))
292 done
293 # Allow user to interactively (de-)select any of the entries
294 echo
295 printf "Select mount points that you want to be included or press %s" \
296 "SPACE to continue"
297 c="$(getkey | tr a-z A-Z)"
298 [ "$c" == " " ] && { echo; echo; break; }
299 if [ -z "$c" ] ||
300 [ "$c" '<' 'A' -o $(ord "$c") -gt $((64 + $(ord "$j"))) ]; then
301 # Invalid input, ring the console bell
302 tput bel
303 else
304 # Toggle the selection for the given entry
305 if echo "$sel" | grep -qs $c; then
306 sel="$(printf "$sel" | sed "s/$c//")"
307 else
308 sel="$sel$c"
309 fi
310 fi
311 # Reposition cursor to the top of the list of entries
312 tput cuu $(($j + 1))
313 echo
314 done
315 fi
316 j=1; for m in ${mounts}; do
317 c="$(chr $(($j + 64)))"
318 if echo "$sel" | grep -qs $c; then
319 bind_mounts="${bind_mounts}$m $m none rw,bind 0 0
320"
321 fi
322 j=$(($j+1))
323 done
324fi
325
[email protected]47b16752010-08-31 05:01:15326# Remove stale entry from /etc/schroot/schroot.conf. Entries start
327# with the target name in square brackets, followed by an arbitrary
328# number of lines. The entry stops when either the end of file has
329# been reached, or when the beginning of a new target is encountered.
330# This means, we cannot easily match for a range of lines in
331# "sed". Instead, we actually have to iterate over each line and check
332# whether it is the beginning of a new entry.
333sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
334 /etc/schroot/schroot.conf
335
336# Download base system. This takes some time
[email protected]04aea5a2010-10-15 00:40:39337if [ -z "${mirror}" ]; then
[email protected]757c2962012-03-15 19:05:18338 grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
[email protected]04aea5a2010-10-15 00:40:39339 mirror="http://archive.ubuntu.com/ubuntu" ||
340 mirror="http://ftp.us.debian.org/debian"
341fi
[email protected]bb2c63a2012-05-09 18:31:56342
343sudo ${http_proxy:+http_proxy="${http_proxy}"} debootstrap ${archflag} \
344 "${distname}" "/var/lib/chroot/${target}" "$mirror"
[email protected]47b16752010-08-31 05:01:15345
346# Add new entry to /etc/schroot/schroot.conf
[email protected]757c2962012-03-15 19:05:18347grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
[email protected]47b16752010-08-31 05:01:15348 brand="Ubuntu" || brand="Debian"
[email protected]6a617002010-10-15 20:56:22349if [ -z "${chroot_groups}" ]; then
[email protected]757c2962012-03-15 19:05:18350 chroot_groups="${admin},$(id -gn)"
[email protected]6a617002010-10-15 20:56:22351fi
[email protected]757c2962012-03-15 19:05:18352# Older versions of schroot wanted a "priority=" line, whereas recent
353# versions deprecate "priority=" and warn if they see it. We don't have
354# a good feature test, but scanning for the string "priority=" in the
355# existing "schroot.conf" file is a good indication of what to do.
356priority=$(grep -qs 'priority=' /etc/schroot/schroot.conf &&
357 echo 'priority=3' || :)
[email protected]47b16752010-08-31 05:01:15358sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
359[${target%bit}]
360description=${brand} ${distname} ${arch}
361type=directory
362directory=/var/lib/chroot/${target}
[email protected]47b16752010-08-31 05:01:15363users=root
[email protected]6a617002010-10-15 20:56:22364groups=${chroot_groups}
365root-groups=${chroot_groups}
[email protected]47b16752010-08-31 05:01:15366personality=linux$([ "${arch}" != 64bit ] && echo 32)
367script-config=script-${target}
[email protected]757c2962012-03-15 19:05:18368${priority}
[email protected]47b16752010-08-31 05:01:15369
370EOF
371
[email protected]757c2962012-03-15 19:05:18372# Set up a list of mount points that is specific to this
373# chroot environment.
374sed '/^FSTAB=/s,"[^"]*","/etc/schroot/mount-'"${target}"'",' \
[email protected]47b16752010-08-31 05:01:15375 /etc/schroot/script-defaults |
376 sudo sh -c 'cat >/etc/schroot/script-'"${target}"
[email protected]b24c3dc2012-02-29 22:08:46377sed '\,^/home[/[:space:]],s/\([,[:space:]]\)bind[[:space:]]/\1rbind /' \
378 /etc/schroot/mount-defaults |
379 sudo sh -c 'cat > /etc/schroot/mount-'"${target}"
[email protected]757c2962012-03-15 19:05:18380
381# Add the extra mount points that the user told us about
382[ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
383 printf "${bind_mounts}" |
384 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
385
386# If this system has a "/media" mountpoint, import it into the chroot
387# environment. Most modern distributions use this mount point to
388# automatically mount devices such as CDROMs, USB sticks, etc...
389if [ -d /media ] &&
390 ! grep -qs '^/media' /etc/schroot/mount-"${target}"; then
391 echo '/media /media none rw,rbind 0 0' |
392 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
393fi
394
[email protected]d0debcc2012-12-21 02:58:34395# Share /dev/shm, /run and /run/shm.
[email protected]757c2962012-03-15 19:05:18396grep -qs '^/dev/shm' /etc/schroot/mount-"${target}" ||
397 echo '/dev/shm /dev/shm none rw,bind 0 0' |
398 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
[email protected]d0debcc2012-12-21 02:58:34399if [ ! -d "/var/lib/chroot/${target}/run" ] &&
400 ! grep -qs '^/run' /etc/schroot/mount-"${target}"; then
401 echo '/run /run none rw,bind 0 0' |
402 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
403fi
404if ! grep -qs '^/run/shm' /etc/schroot/mount-"${target}"; then
[email protected]757c2962012-03-15 19:05:18405 { [ -d /run ] && echo '/run/shm /run/shm none rw,bind 0 0' ||
406 echo '/dev/shm /run/shm none rw,bind 0 0'; } |
407 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
408fi
409
410# Set up a special directory that changes contents depending on the target
411# that is executing.
412d="$(readlink -f "${HOME}/chroot" 2>/dev/null || echo "${HOME}/chroot")"
413s="${d}/.${target}"
414echo "${s} ${d} none rw,bind 0 0" |
[email protected]47b16752010-08-31 05:01:15415 sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
[email protected]757c2962012-03-15 19:05:18416mkdir -p "${s}"
[email protected]47b16752010-08-31 05:01:15417
418# Install a helper script to launch commands in the chroot
[email protected]757c2962012-03-15 19:05:18419sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<'EOF'
[email protected]47b16752010-08-31 05:01:15420#!/bin/bash
[email protected]757c2962012-03-15 19:05:18421
422chroot="${0##*/}"
423
424wrap() {
425 # Word-wrap the text passed-in on stdin. Optionally, on continuation lines
426 # insert the same number of spaces as the number of characters in the
427 # parameter(s) passed to this function.
428 # If the "fold" program cannot be found, or if the actual width of the
429 # terminal cannot be determined, this function doesn't attempt to do any
430 # wrapping.
431 local f="$(type -P fold)"
432 [ -z "${f}" ] && { cat; return; }
433 local c="$(stty -a </dev/tty 2>/dev/null |
434 sed 's/.*columns[[:space:]]*\([0-9]*\).*/\1/;t;d')"
435 [ -z "${c}" ] && { cat; return; }
436 local i="$(echo "$*"|sed 's/./ /g')"
437 local j="$(printf %s "${i}"|wc -c)"
438 if [ "${c}" -gt "${j}" ]; then
439 dd bs=1 count="${j}" 2>/dev/null
440 "${f}" -sw "$((${c}-${j}))" | sed '2,$s/^/'"${i}"'/'
441 else
442 "${f}" -sw "${c}"
443 fi
444}
445
446help() {
447 echo "Usage ${0##*/} [-h|--help] [-c|--clean] [-C|--clean-all] [-l|--list] [--] args" | wrap "Usage ${0##*/} "
448 echo " help: print this message" | wrap " "
449 echo " list: list all known chroot environments" | wrap " "
450 echo " clean: remove all old chroot sessions for \"${chroot}\"" | wrap " "
451 echo " clean-all: remove all old chroot sessions for all environments" | wrap " "
452 exit 0
453}
454
455clean() {
456 local s t rc
457 rc=0
458 for s in $(schroot -l --all-sessions); do
459 if [ -n "$1" ]; then
460 t="${s#session:}"
461 [ "${t#${chroot}-}" == "${t}" ] && continue
462 fi
463 if ls -l /proc/*/{cwd,fd} 2>/dev/null |
464 fgrep -qs "/var/lib/schroot/mount/${t}"; then
465 echo "Session \"${t}\" still has active users, not cleaning up" | wrap
466 rc=1
467 continue
468 fi
[email protected]b11411c2012-03-21 22:09:41469 sudo schroot -c "${s}" -e || rc=1
[email protected]757c2962012-03-15 19:05:18470 done
471 exit ${rc}
472}
473
474list() {
475 for e in $(schroot -l); do
476 e="${e#chroot:}"
477 [ -x "/usr/local/bin/${e}" ] || continue
478 if schroot -l --all-sessions 2>/dev/null |
479 sed 's/^session://' |
480 grep -qs "^${e}-"; then
481 echo "${e} is currently active"
482 else
483 echo "${e}"
484 fi
485 done
486 exit 0
487}
488
489while [ "$#" -ne 0 ]; do
490 case "$1" in
491 --) shift; break;;
492 -h|--help) shift; help;;
493 -l|--list) shift; list;;
494 -c|--clean) shift; clean "${chroot}";;
495 -C|--clean-all) shift; clean;;
496 *) break;;
497 esac
498done
499
[email protected]6538c872013-07-23 05:36:07500# Start a new chroot session and keep track of the session id. We inject this
501# id into all processes that run inside the chroot. Unless they go out of their
502# way to clear their environment, we can then later identify our child and
503# grand-child processes by scanning their environment.
[email protected]757c2962012-03-15 19:05:18504session="$(schroot -c "${chroot}" -b)"
[email protected]6538c872013-07-23 05:36:07505export CHROOT_SESSION_ID="${session}"
[email protected]757c2962012-03-15 19:05:18506
yyanagisawa53d09732014-10-09 07:18:14507# Set GOMA_TMP_DIR for better handling of goma inside chroot.
508export GOMA_TMP_DIR="/tmp/goma_tmp_$CHROOT_SESSION_ID"
509mkdir -p "$GOMA_TMP_DIR"
510
[email protected]757c2962012-03-15 19:05:18511if [ $# -eq 0 ]; then
[email protected]6538c872013-07-23 05:36:07512 # Run an interactive shell session
[email protected]757c2962012-03-15 19:05:18513 schroot -c "${session}" -r -p
[email protected]47b16752010-08-31 05:01:15514else
[email protected]6538c872013-07-23 05:36:07515 # Run a command inside of the chroot environment
[email protected]757c2962012-03-15 19:05:18516 p="$1"; shift
517 schroot -c "${session}" -r -p "$p" -- "$@"
[email protected]47b16752010-08-31 05:01:15518fi
[email protected]757c2962012-03-15 19:05:18519rc=$?
520
[email protected]6538c872013-07-23 05:36:07521# Compute the inode of the root directory inside of the chroot environment.
[email protected]757c2962012-03-15 19:05:18522i=$(schroot -c "${session}" -r -p ls -- -id /proc/self/root/. |
523 awk '{ print $1 }') 2>/dev/null
[email protected]6538c872013-07-23 05:36:07524other_pids=
[email protected]757c2962012-03-15 19:05:18525while [ -n "$i" ]; do
[email protected]6538c872013-07-23 05:36:07526 # Identify processes by the inode number of their root directory. Then
527 # remove all processes that we know belong to other sessions. We use
528 # "sort | uniq -u" to do what amounts to a "set substraction operation".
529 pids=$({ ls -id1 /proc/*/root/. 2>/dev/null |
[email protected]757c2962012-03-15 19:05:18530 sed -e 's,^[^0-9]*'$i'.*/\([1-9][0-9]*\)/.*$,\1,
531 t
[email protected]6538c872013-07-23 05:36:07532 d';
533 echo "${other_pids}";
534 echo "${other_pids}"; } | sort | uniq -u) >/dev/null 2>&1
535 # Kill all processes that are still left running in the session. This is
536 # typically an assortment of daemon processes that were started
537 # automatically. They result in us being unable to tear down the session
538 # cleanly.
539 [ -z "${pids}" ] && break
540 for j in $pids; do
541 # Unfortunately, the way that schroot sets up sessions has the
542 # side-effect of being unable to tell one session apart from another.
543 # This can result in us attempting to kill processes in other sessions.
544 # We make a best-effort to avoid doing so.
545 k="$( ( xargs -0 -n1 </proc/$j/environ ) 2>/dev/null |
546 sed 's/^CHROOT_SESSION_ID=/x/;t1;d;:1;q')"
547 if [ -n "${k}" -a "${k#x}" != "${session}" ]; then
548 other_pids="${other_pids}
549${j}"
550 continue
551 fi
552 kill -9 $pids
553 done
[email protected]757c2962012-03-15 19:05:18554done
[email protected]6538c872013-07-23 05:36:07555# End the chroot session. This should clean up all temporary files. But if we
556# earlier failed to terminate all (daemon) processes inside of the session,
557# deleting the session could fail. When that happens, the user has to manually
558# clean up the stale files by invoking us with "--clean" after having killed
559# all running processes.
[email protected]757c2962012-03-15 19:05:18560schroot -c "${session}" -e
yyanagisawa53d09732014-10-09 07:18:14561# Since no goma processes are running, we can remove goma directory.
562rm -rf "$GOMA_TMP_DIR"
[email protected]757c2962012-03-15 19:05:18563exit $rc
[email protected]47b16752010-08-31 05:01:15564EOF
565sudo chown root:root /usr/local/bin/"${target%bit}"
566sudo chmod 755 /usr/local/bin/"${target%bit}"
567
[email protected]04aea5a2010-10-15 00:40:39568# Add the standard Ubuntu update repositories if requested.
[email protected]8eb22e92010-10-20 03:32:17569[ "${alt_repos}" = "y" -a \
570 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
[email protected]04aea5a2010-10-15 00:40:39571sudo sed -i '/^deb .* [^ -]\+ main$/p
572 s/^\(deb .* [^ -]\+\) main/\1-security main/
573 p
574 t1
575 d
576 :1;s/-security main/-updates main/
577 t
578 d' "/var/lib/chroot/${target}/etc/apt/sources.list"
579
[email protected]47b16752010-08-31 05:01:15580# Add a few more repositories to the chroot
[email protected]757c2962012-03-15 19:05:18581[ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
582sudo sed -i 's/ main$/ main restricted universe multiverse/' \
583 "/var/lib/chroot/${target}/etc/apt/sources.list"
584
585# Add the Ubuntu "partner" repository, if available
586if [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
587 HEAD "http://archive.canonical.com/ubuntu/dists/${distname}/partner" \
588 >&/dev/null; then
589 sudo sh -c '
590 echo "deb http://archive.canonical.com/ubuntu" \
591 "'"${distname}"' partner" \
592 >>"/var/lib/chroot/'"${target}"'/etc/apt/sources.list"'
593fi
594
595# Add source repositories, if the user requested we do so
[email protected]8eb22e92010-10-20 03:32:17596[ "${add_srcs}" = "y" -a \
597 -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
[email protected]757c2962012-03-15 19:05:18598sudo sed -i '/^deb[^-]/p
599 s/^deb\([^-]\)/deb-src\1/' \
600 "/var/lib/chroot/${target}/etc/apt/sources.list"
[email protected]47b16752010-08-31 05:01:15601
[email protected]bb2c63a2012-05-09 18:31:56602# Set apt proxy if host has set http_proxy
603if [ -n "${http_proxy}" ]; then
604 sudo sh -c '
605 echo "Acquire::http::proxy \"'"${http_proxy}"'\";" \
606 >>"/var/lib/chroot/'"${target}"'/etc/apt/apt.conf"'
607fi
608
[email protected]47b16752010-08-31 05:01:15609# Update packages
[email protected]757c2962012-03-15 19:05:18610sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
[email protected]47b16752010-08-31 05:01:15611 apt-get update; apt-get -y dist-upgrade' || :
612
613# Install a couple of missing packages
614for i in debian-keyring ubuntu-keyring locales sudo; do
615 [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
[email protected]757c2962012-03-15 19:05:18616 sudo "/usr/local/bin/${target%bit}" apt-get -y install "$i" || :
[email protected]47b16752010-08-31 05:01:15617done
618
619# Configure locales
[email protected]757c2962012-03-15 19:05:18620sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
[email protected]47b16752010-08-31 05:01:15621 l='"${LANG:-en_US}"'; l="${l%%.*}"
622 [ -r /etc/locale.gen ] &&
623 sed -i "s/^# \($l\)/\1/" /etc/locale.gen
624 locale-gen $LANG en_US en_US.UTF-8' || :
625
[email protected]757c2962012-03-15 19:05:18626# Enable multi-arch support, if available
627sudo "/usr/local/bin/${target%bit}" dpkg --assert-multi-arch >&/dev/null &&
628 [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && {
629 sudo sed -i 's/ / [arch=amd64,i386] /' \
630 "/var/lib/chroot/${target}/etc/apt/sources.list"
631 [ -d /var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/ ] &&
[email protected]e9216772012-12-22 00:51:00632 sudo "/usr/local/bin/${target%bit}" dpkg --add-architecture \
633 $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) >&/dev/null ||
634 echo foreign-architecture \
635 $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) |
636 sudo sh -c \
637 "cat >'/var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/multiarch'"
[email protected]757c2962012-03-15 19:05:18638}
639
[email protected]47b16752010-08-31 05:01:15640# Configure "sudo" package
[email protected]757c2962012-03-15 19:05:18641sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
642 egrep -qs '"'^$(id -nu) '"' /etc/sudoers ||
[email protected]47b16752010-08-31 05:01:15643 echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'
644
645# Install a few more commonly used packages
[email protected]757c2962012-03-15 19:05:18646sudo "/usr/local/bin/${target%bit}" apt-get -y install \
[email protected]47b16752010-08-31 05:01:15647 autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool \
yyanagisawa9061716a2014-10-08 06:25:40648 lsof strace
[email protected]47b16752010-08-31 05:01:15649
650# If running a 32bit environment on a 64bit machine, install a few binaries
[email protected]8eb22e92010-10-20 03:32:17651# as 64bit. This is only done automatically if the chroot distro is the same as
652# the host, otherwise there might be incompatibilities in build settings or
653# runtime dependencies. The user can force it with the '-c' flag.
[email protected]757c2962012-03-15 19:05:18654host_distro=$(grep -s DISTRIB_CODENAME /etc/lsb-release | \
[email protected]8eb22e92010-10-20 03:32:17655 cut -d "=" -f 2)
656if [ "${copy_64}" = "y" -o \
657 "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \
658 file /bin/bash 2>/dev/null | grep -q x86-64; then
[email protected]757c2962012-03-15 19:05:18659 readlinepkg=$(sudo "/usr/local/bin/${target%bit}" sh -c \
[email protected]42c58a42010-10-15 15:18:16660 'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1')
[email protected]757c2962012-03-15 19:05:18661 sudo "/usr/local/bin/${target%bit}" apt-get -y install \
yyanagisawadc73b4a2014-10-17 08:45:49662 lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1 lib64stdc++6
[email protected]47b16752010-08-31 05:01:15663 dep=
[email protected]757c2962012-03-15 19:05:18664 for i in binutils gdb; do
[email protected]47b16752010-08-31 05:01:15665 [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
666 done
667 [ -n "$dep" ] && sudo apt-get -y install $dep
[email protected]757c2962012-03-15 19:05:18668 sudo mkdir -p "/var/lib/chroot/${target}/usr/local/lib/amd64"
[email protected]47b16752010-08-31 05:01:15669 for i in libbfd libpython; do
670 lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
[email protected]757c2962012-03-15 19:05:18671 grep -s "$i" | awk '{ print $3 }')"
[email protected]47b16752010-08-31 05:01:15672 if [ -n "$lib" -a -r "$lib" ]; then
[email protected]757c2962012-03-15 19:05:18673 sudo cp "$lib" "/var/lib/chroot/${target}/usr/local/lib/amd64"
[email protected]47b16752010-08-31 05:01:15674 fi
675 done
676 for lib in libssl libcrypt; do
[email protected]757c2962012-03-15 19:05:18677 for path in /usr/lib /usr/lib/x86_64-linux-gnu; do
678 sudo cp $path/$lib* \
679 "/var/lib/chroot/${target}/usr/local/lib/amd64/" >&/dev/null || :
680 done
681 done
682 for i in gdb ld; do
683 sudo cp /usr/bin/$i "/var/lib/chroot/${target}/usr/local/lib/amd64/"
684 sudo sh -c "cat >'/var/lib/chroot/${target}/usr/local/bin/$i'" <<EOF
685#!/bin/sh
686exec /lib64/ld-linux-x86-64.so.2 --library-path /usr/local/lib/amd64 \
687 /usr/local/lib/amd64/$i "\$@"
688EOF
689 sudo chmod 755 "/var/lib/chroot/${target}/usr/local/bin/$i"
690 done
691fi
692
693
694# If the install-build-deps.sh script can be found, offer to run it now
695script="$(dirname $(readlink -f "$0"))/install-build-deps.sh"
696if [ -x "${script}" ]; then
697 while :; do
698 echo
699 echo "If you plan on building Chrome inside of the new chroot environment,"
700 echo "you now have to install the build dependencies. Do you want me to"
701 printf "start the script that does this for you (y/n)? "
702 read install_deps
703 case "${install_deps}" in
704 y|Y)
705 echo
706 # We prefer running the script in-place, but this might not be
707 # possible, if it lives on a network filesystem that denies
708 # access to root.
709 tmp_script=
[email protected]d8185032012-10-17 16:47:59710 if ! sudo /usr/local/bin/"${target%bit}" \
711 sh -c "[ -x '${script}' ]" >&/dev/null; then
[email protected]757c2962012-03-15 19:05:18712 tmp_script="/tmp/${script##*/}"
713 cp "${script}" "${tmp_script}"
714 fi
715 # Some distributions automatically start an instance of the system-
[email protected]8a8b66f12012-10-17 16:45:29716 # wide dbus daemon, cron daemon or of the logging daemon, when
717 # installing the Chrome build depencies. This prevents the chroot
718 # session from being closed. So, we always try to shut down any running
719 # instance of dbus and rsyslog.
720 sudo /usr/local/bin/"${target%bit}" sh -c "${script} --no-lib32;
[email protected]757c2962012-03-15 19:05:18721 rc=$?;
[email protected]8a8b66f12012-10-17 16:45:29722 /etc/init.d/cron stop >/dev/null 2>&1 || :;
[email protected]b11411c2012-03-21 22:09:41723 /etc/init.d/rsyslog stop >/dev/null 2>&1 || :;
[email protected]757c2962012-03-15 19:05:18724 /etc/init.d/dbus stop >/dev/null 2>&1 || :;
725 exit $rc"
726 rc=$?
727 [ -n "${tmp_script}" ] && rm -f "${tmp_script}"
728 [ $rc -ne 0 ] && exit $rc
729 break
730 ;;
731 n|N)
732 break
733 ;;
734 esac
735 done
736 echo
737fi
738
739# Check whether ~/chroot is on a (slow) network file system and offer to
740# relocate it. Also offer relocation, if the user appears to have multiple
741# spindles (as indicated by "${bind_mount}" being non-empty).
742# We only offer this option, if it doesn't look as if a chroot environment
743# is currently active. Otherwise, relocation is unlikely to work and it
744# can be difficult for the user to recover from the failed attempt to relocate
745# the ~/chroot directory.
746# We don't aim to solve this problem for every configuration,
747# but try to help with the common cases. For more advanced configuration
748# options, the user can always manually adjust things.
749mkdir -p "${HOME}/chroot/"
750if [ ! -h "${HOME}/chroot" ] &&
751 ! egrep -qs '^[^[:space:]]*/chroot' /etc/fstab &&
752 { [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] ||
753 is_network_drive "${HOME}/chroot"; } &&
754 ! egrep -qs '/var/lib/[^/]*chroot/.*/chroot' /proc/mounts; then
755 echo "${HOME}/chroot is currently located on the same device as your"
756 echo "home directory."
757 echo "This might not be what you want. Do you want me to move it somewhere"
758 echo "else?"
759 # If the computer has multiple spindles, many users configure all or part of
760 # the secondary hard disk to be writable by the primary user of this machine.
761 # Make some reasonable effort to detect this type of configuration and
762 # then offer a good location for where to put the ~/chroot directory.
763 suggest=
764 for i in $(echo "${bind_mounts}"|cut -d ' ' -f 1); do
765 if [ -d "$i" -a -w "$i" -a \( ! -a "$i/chroot" -o -w "$i/chroot/." \) ] &&
766 ! is_network_drive "$i"; then
767 suggest="$i"
768 else
769 for j in "$i/"*; do
770 if [ -d "$j" -a -w "$j" -a \
771 \( ! -a "$j/chroot" -o -w "$j/chroot/." \) ] &&
772 ! is_network_drive "$j"; then
773 suggest="$j"
774 else
775 for k in "$j/"*; do
776 if [ -d "$k" -a -w "$k" -a \
777 \( ! -a "$k/chroot" -o -w "$k/chroot/." \) ] &&
778 ! is_network_drive "$k"; then
779 suggest="$k"
780 break
781 fi
782 done
783 fi
784 [ -n "${suggest}" ] && break
785 done
786 fi
787 [ -n "${suggest}" ] && break
788 done
789 def_suggest="${HOME}"
790 if [ -n "${suggest}" ]; then
791 # For home directories that reside on network drives, make our suggestion
792 # the default option. For home directories that reside on a local drive,
793 # require that the user manually enters the new location.
794 if is_network_drive "${HOME}"; then
795 def_suggest="${suggest}"
796 else
797 echo "A good location would probably be in \"${suggest}\""
798 fi
799 fi
800 while :; do
801 printf "Physical location [${def_suggest}]: "
802 read dir
803 [ -z "${dir}" ] && dir="${def_suggest}"
804 [ "${dir%%/}" == "${HOME%%/}" ] && break
805 if ! [ -d "${dir}" -a -w "${dir}" ] ||
806 [ -a "${dir}/chroot" -a ! -w "${dir}/chroot/." ]; then
807 echo "Cannot write to ${dir}/chroot. Please try again"
808 else
809 mv "${HOME}/chroot" "${dir}/chroot"
810 ln -s "${dir}/chroot" "${HOME}/chroot"
811 for i in $(list_all_chroots); do
812 sudo "$i" mkdir -p "${dir}/chroot"
813 done
814 sudo sed -i "s,${HOME}/chroot,${dir}/chroot,g" /etc/schroot/mount-*
815 break
816 fi
[email protected]47b16752010-08-31 05:01:15817 done
818fi
819
820# Clean up package files
[email protected]ced8fddb2012-12-05 03:35:56821sudo schroot -c "${target%bit}" -p -- apt-get clean
[email protected]47b16752010-08-31 05:01:15822sudo apt-get clean
823
[email protected]757c2962012-03-15 19:05:18824trap '' INT TERM QUIT HUP
[email protected]47b16752010-08-31 05:01:15825trap '' EXIT
[email protected]757c2962012-03-15 19:05:18826
827# Let the user know what we did
[email protected]47b16752010-08-31 05:01:15828cat <<EOF
829
830
831Successfully installed ${distname} ${arch}
832
[email protected]d8185032012-10-17 16:47:59833You can run programs inside of the chroot by invoking the
834"/usr/local/bin/${target%bit}" command.
[email protected]47b16752010-08-31 05:01:15835
[email protected]757c2962012-03-15 19:05:18836This command can be used with arguments, in order to just run a single
837program inside of the chroot environment (e.g. "${target%bit} make chrome")
838or without arguments, in order to run an interactive shell session inside
839of the chroot environment.
840
841If you need to run things as "root", you can use "sudo" (e.g. try
842"sudo ${target%bit} apt-get update").
843
844Your home directory is shared between the host and the chroot. But I
845configured "${HOME}/chroot" to be private to the chroot environment.
846You can use it for files that need to differ between environments. This
847would be a good place to store binaries that you have built from your
848source files.
849
850For Chrome, this probably means you want to make your "out" directory a
851symbolic link that points somewhere inside of "${HOME}/chroot".
852
853You still need to run "gclient runhooks" whenever you switch from building
854outside of the chroot to inside of the chroot. But you will find that you
855don't have to repeatedly erase and then completely rebuild all your object
856and binary files.
857
[email protected]47b16752010-08-31 05:01:15858EOF