OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |