[M120 Migration][VD] Fix url crash in RequestCertificateConfirm
[platform/framework/web/chromium-efl.git] / build / install-chroot.sh
1 #!/bin/bash -e
2
3 # Copyright 2012 The Chromium Authors
4 # 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
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 preferred name of the
16 # administrator group.
17 admin=$(grep '^admin:' /etc/group >&/dev/null && echo admin || echo adm)
18
19 usage() {
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"
24   echo "-g group,... groups that can use the chroot unauthenticated"
25   echo "             Default: '${admin}' and current user's group ('$(id -gn)')"
26   echo "-l           List all installed chroot environments"
27   echo "-m mirror    an alternate repository mirror for package downloads"
28   echo "-s           configure default deb-srcs"
29   echo "-c           always copy 64bit helper binaries to 32bit chroot"
30   echo "-h           this help message"
31 }
32
33 process_opts() {
34   local OPTNAME OPTIND OPTERR OPTARG
35   while getopts ":b:g:lm:sch" OPTNAME; do
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 -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         ;;
51       g)
52         [ -n "${OPTARG}" ] &&
53           chroot_groups="${chroot_groups}${chroot_groups:+,}${OPTARG}"
54         ;;
55       l)
56         list_all_chroots
57         exit
58         ;;
59       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         ;;
67       s)
68         add_srcs="y"
69         ;;
70       c)
71         copy_64="y"
72         ;;
73       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
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 -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
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 -qs '^nfs|cifs|smbfs'
128 }
129
130 # 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 }
136
137 process_opts "$@"
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
144 # Error handler
145 trap 'exit 1' INT TERM QUIT HUP
146 trap '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.
153 dep=
154 for i in dchroot debootstrap libwww-perl; do
155   [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
156 done
157 [ -n "$dep" ] && sudo apt-get -y install $dep
158 sudo apt-get -y install schroot
159
160 # Create directory for chroot
161 sudo mkdir -p /var/lib/chroot
162
163 # Find chroot environments that can be installed with debootstrap
164 targets="$(cd /usr/share/debootstrap/scripts
165            ls | grep '^[a-z]*$')"
166
167 # Ask user to pick one of the available targets
168 echo "The following targets are available to be installed in a chroot:"
169 j=1; for i in $targets; do
170   printf '%4d: %s\n' "$j" "$i"
171   j=$(($j+1))
172 done
173 while :; do
174   printf "Which target would you like to install: "
175   read n
176   [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break
177 done
178 j=1; for i in $targets; do
179   [ "$j" -eq "$n" ] && { distname="$i"; break; }
180   j=$(($j+1))
181 done
182 echo
183
184 # On x86-64, ask whether the user wants to install x86-32 or x86-64
185 archflag=
186 arch=
187 if [ "$(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"
197   echo
198 fi
199 target="${distname}${arch}"
200
201 # Don't accidentally overwrite an existing installation
202 [ -d /var/lib/chroot/"${target}" ] && {
203   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;;
223       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                        "/etc/schroot/${target}"
228            sudo sed -ni '/^[[]'"${target%bit}"']$/,${
229                          :1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
230                        "/etc/schroot/schroot.conf"
231            trap '' INT TERM QUIT HUP
232            trap '' EXIT
233            echo "Deleted!"
234            exit 0;;
235     esac
236   done
237   echo
238 }
239 sudo mkdir -p /var/lib/chroot/"${target}"
240
241 # Offer to include additional standard repositories for Ubuntu-based chroots.
242 alt_repos=
243 grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" && {
244   while :; do
245     echo "Would you like to add ${distname}-updates and ${distname}-security "
246     printf "to the chroot's sources.list (y/n)? "
247     read alt_repos
248     case "${alt_repos}" in
249       y|Y)
250         alt_repos="y"
251         break
252       ;;
253       n|N)
254         break
255       ;;
256     esac
257   done
258   echo
259 }
260
261 # Check for non-standard file system mount points and ask the user whether
262 # they should be imported into the chroot environment
263 # We limit to the first 26 mount points that much some basic heuristics,
264 # because a) that allows us to enumerate choices with a single character,
265 # and b) if we find more than 26 mount points, then these are probably
266 # false-positives and something is very unusual about the system's
267 # configuration. No need to spam the user with even more information that
268 # is likely completely irrelevant.
269 if [ -z "${bind_mounts}" ]; then
270   mounts="$(awk '$2 != "/" && $2 !~ "^/boot" && $2 !~ "^/home" &&
271                  $2 !~ "^/media" && $2 !~ "^/run" &&
272                  ($3 ~ "ext[2-4]" || $3 == "reiserfs" || $3 == "btrfs" ||
273                  $3 == "xfs" || $3 == "jfs" || $3 == "u?msdos" ||
274                  $3 == "v?fat" || $3 == "hfs" || $3 == "ntfs" ||
275                  $3 ~ "nfs[4-9]?" || $3 == "smbfs" || $3 == "cifs") {
276                    print $2
277                  }' /proc/mounts |
278             head -n26)"
279   if [ -n "${mounts}" ]; then
280     echo "You appear to have non-standard mount points that you"
281     echo "might want to import into the chroot environment:"
282     echo
283     sel=
284     while :; do
285       # Print a menu, listing all non-default mounts of local or network
286       # file systems.
287       j=1; for m in ${mounts}; do
288         c="$(printf $(printf '\\%03o' $((64+$j))))"
289         echo "$sel" | grep -qs $c &&
290           state="mounted in chroot" || state="$(tput el)"
291         printf "   $c) %-40s${state}\n" "$m"
292         j=$(($j+1))
293       done
294       # Allow user to interactively (de-)select any of the entries
295       echo
296       printf "Select mount points that you want to be included or press %s" \
297              "SPACE to continue"
298       c="$(getkey | tr a-z A-Z)"
299       [ "$c" == " " ] && { echo; echo; break; }
300       if [ -z "$c" ] ||
301          [ "$c" '<' 'A' -o $(ord "$c") -gt $((64 + $(ord "$j"))) ]; then
302           # Invalid input, ring the console bell
303           tput bel
304       else
305         # Toggle the selection for the given entry
306         if echo "$sel" | grep -qs $c; then
307           sel="$(printf "$sel" | sed "s/$c//")"
308         else
309           sel="$sel$c"
310         fi
311       fi
312       # Reposition cursor to the top of the list of entries
313       tput cuu $(($j + 1))
314       echo
315     done
316   fi
317   j=1; for m in ${mounts}; do
318     c="$(chr $(($j + 64)))"
319     if echo "$sel" | grep -qs $c; then
320       bind_mounts="${bind_mounts}$m $m none rw,bind 0 0
321 "
322     fi
323     j=$(($j+1))
324   done
325 fi
326
327 # Remove stale entry from /etc/schroot/schroot.conf. Entries start
328 # with the target name in square brackets, followed by an arbitrary
329 # number of lines. The entry stops when either the end of file has
330 # been reached, or when the beginning of a new target is encountered.
331 # This means, we cannot easily match for a range of lines in
332 # "sed". Instead, we actually have to iterate over each line and check
333 # whether it is the beginning of a new entry.
334 sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p'       \
335          /etc/schroot/schroot.conf
336
337 # Download base system. This takes some time
338 if [ -z "${mirror}" ]; then
339  grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
340    mirror="http://archive.ubuntu.com/ubuntu" ||
341    mirror="http://ftp.us.debian.org/debian"
342 fi
343
344 sudo ${http_proxy:+http_proxy="${http_proxy}"} debootstrap ${archflag} \
345     "${distname}" "/var/lib/chroot/${target}"  "$mirror"
346
347 # Add new entry to /etc/schroot/schroot.conf
348 grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
349   brand="Ubuntu" || brand="Debian"
350 if [ -z "${chroot_groups}" ]; then
351   chroot_groups="${admin},$(id -gn)"
352 fi
353
354 if [ -d '/etc/schroot/default' ]; then
355   new_version=1
356   fstab="/etc/schroot/${target}/fstab"
357 else
358   new_version=0
359   fstab="/etc/schroot/mount-${target}"
360 fi
361
362 if [ "$new_version" = "1" ]; then
363   sudo cp -ar /etc/schroot/default /etc/schroot/${target}
364
365   sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
366 [${target%bit}]
367 description=${brand} ${distname} ${arch}
368 type=directory
369 directory=/var/lib/chroot/${target}
370 users=root
371 groups=${chroot_groups}
372 root-groups=${chroot_groups}
373 personality=linux$([ "${arch}" != 64bit ] && echo 32)
374 profile=${target}
375
376 EOF
377   [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
378     printf "${bind_mounts}" |
379       sudo sh -c "cat >>${fstab}"
380 else
381   # Older versions of schroot wanted a "priority=" line, whereas recent
382   # versions deprecate "priority=" and warn if they see it. We don't have
383   # a good feature test, but scanning for the string "priority=" in the
384   # existing "schroot.conf" file is a good indication of what to do.
385   priority=$(grep -qs 'priority=' /etc/schroot/schroot.conf &&
386            echo 'priority=3' || :)
387   sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
388 [${target%bit}]
389 description=${brand} ${distname} ${arch}
390 type=directory
391 directory=/var/lib/chroot/${target}
392 users=root
393 groups=${chroot_groups}
394 root-groups=${chroot_groups}
395 personality=linux$([ "${arch}" != 64bit ] && echo 32)
396 script-config=script-${target}
397 ${priority}
398
399 EOF
400
401   # Set up a list of mount points that is specific to this
402   # chroot environment.
403   sed '/^FSTAB=/s,"[^"]*","'"${fstab}"'",' \
404            /etc/schroot/script-defaults |
405     sudo sh -c 'cat >/etc/schroot/script-'"${target}"
406   sed '\,^/home[/[:space:]],s/\([,[:space:]]\)bind[[:space:]]/\1rbind /' \
407     /etc/schroot/mount-defaults |
408     sudo sh -c "cat > ${fstab}"
409 fi
410
411 # Add the extra mount points that the user told us about
412 [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
413   printf "${bind_mounts}" |
414     sudo sh -c 'cat >>'"${fstab}"
415
416 # If this system has a "/media" mountpoint, import it into the chroot
417 # environment. Most modern distributions use this mount point to
418 # automatically mount devices such as CDROMs, USB sticks, etc...
419 if [ -d /media ] &&
420    ! grep -qs '^/media' "${fstab}"; then
421   echo '/media /media none rw,rbind 0 0' |
422     sudo sh -c 'cat >>'"${fstab}"
423 fi
424
425 # Share /dev/shm, /run and /run/shm.
426 grep -qs '^/dev/shm' "${fstab}" ||
427   echo '/dev/shm /dev/shm none rw,bind 0 0' |
428     sudo sh -c 'cat >>'"${fstab}"
429 if [ ! -d "/var/lib/chroot/${target}/run" ] &&
430    ! grep -qs '^/run' "${fstab}"; then
431   echo '/run /run none rw,bind 0 0' |
432     sudo sh -c 'cat >>'"${fstab}"
433 fi
434 if ! grep -qs '^/run/shm' "${fstab}"; then
435   { [ -d /run ] && echo '/run/shm /run/shm none rw,bind 0 0' ||
436                    echo '/dev/shm /run/shm none rw,bind 0 0'; } |
437     sudo sh -c 'cat >>'"${fstab}"
438 fi
439
440 # Set up a special directory that changes contents depending on the target
441 # that is executing.
442 d="$(readlink -f "${HOME}/chroot" 2>/dev/null || echo "${HOME}/chroot")"
443 s="${d}/.${target}"
444 echo "${s} ${d} none rw,bind 0 0" |
445   sudo sh -c 'cat >>'"${target}"
446 mkdir -p "${s}"
447
448 # Install a helper script to launch commands in the chroot
449 sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<'EOF'
450 #!/bin/bash
451
452 chroot="${0##*/}"
453
454 wrap() {
455   # Word-wrap the text passed-in on stdin. Optionally, on continuation lines
456   # insert the same number of spaces as the number of characters in the
457   # parameter(s) passed to this function.
458   # If the "fold" program cannot be found, or if the actual width of the
459   # terminal cannot be determined, this function doesn't attempt to do any
460   # wrapping.
461   local f="$(type -P fold)"
462   [ -z "${f}" ] && { cat; return; }
463   local c="$(stty -a </dev/tty 2>/dev/null |
464              sed 's/.*columns[[:space:]]*\([0-9]*\).*/\1/;t;d')"
465   [ -z "${c}" ] && { cat; return; }
466   local i="$(echo "$*"|sed 's/./ /g')"
467   local j="$(printf %s "${i}"|wc -c)"
468   if [ "${c}" -gt "${j}" ]; then
469     dd bs=1 count="${j}" 2>/dev/null
470     "${f}" -sw "$((${c}-${j}))" | sed '2,$s/^/'"${i}"'/'
471   else
472     "${f}" -sw "${c}"
473   fi
474 }
475
476 help() {
477   echo "Usage ${0##*/} [-h|--help] [-c|--clean] [-C|--clean-all] [-l|--list] [--] args" | wrap "Usage ${0##*/} "
478   echo "  help:      print this message"                                                | wrap "             "
479   echo "  list:      list all known chroot environments"                                | wrap "             "
480   echo "  clean:     remove all old chroot sessions for \"${chroot}\""                  | wrap "             "
481   echo "  clean-all: remove all old chroot sessions for all environments"               | wrap "             "
482   exit 0
483 }
484
485 clean() {
486   local s t rc
487   rc=0
488   for s in $(schroot -l --all-sessions); do
489     if [ -n "$1" ]; then
490       t="${s#session:}"
491       [ "${t#${chroot}-}" == "${t}" ] && continue
492     fi
493     if ls -l /proc/*/{cwd,fd} 2>/dev/null |
494        fgrep -qs "/var/lib/schroot/mount/${t}"; then
495       echo "Session \"${t}\" still has active users, not cleaning up" | wrap
496       rc=1
497       continue
498     fi
499     sudo schroot -c "${s}" -e || rc=1
500   done
501   exit ${rc}
502 }
503
504 list() {
505   for e in $(schroot -l); do
506     e="${e#chroot:}"
507     [ -x "/usr/local/bin/${e}" ] || continue
508     if schroot -l --all-sessions 2>/dev/null |
509        sed 's/^session://' |
510        grep -qs "^${e}-"; then
511       echo "${e} is currently active"
512     else
513       echo "${e}"
514     fi
515   done
516   exit 0
517 }
518
519 while [ "$#" -ne 0 ]; do
520   case "$1" in
521     --)             shift; break;;
522     -h|--help)      shift; help;;
523     -l|--list)      shift; list;;
524     -c|--clean)     shift; clean "${chroot}";;
525     -C|--clean-all) shift; clean;;
526     *)              break;;
527   esac
528 done
529
530 # Start a new chroot session and keep track of the session id. We inject this
531 # id into all processes that run inside the chroot. Unless they go out of their
532 # way to clear their environment, we can then later identify our child and
533 # grand-child processes by scanning their environment.
534 session="$(schroot -c "${chroot}" -b)"
535 export CHROOT_SESSION_ID="${session}"
536
537 # Set GOMA_TMP_DIR for better handling of goma inside chroot.
538 export GOMA_TMP_DIR="/tmp/goma_tmp_$CHROOT_SESSION_ID"
539 mkdir -p "$GOMA_TMP_DIR"
540
541 if [ $# -eq 0 ]; then
542   # Run an interactive shell session
543   schroot -c "${session}" -r -p
544 else
545   # Run a command inside of the chroot environment
546   p="$1"; shift
547   schroot -c "${session}" -r -p "$p" -- "$@"
548 fi
549 rc=$?
550
551 # Compute the inode of the root directory inside of the chroot environment.
552 i=$(schroot -c "${session}" -r -p ls -- -id /proc/self/root/. |
553      awk '{ print $1 }') 2>/dev/null
554 other_pids=
555 while [ -n "$i" ]; do
556   # Identify processes by the inode number of their root directory. Then
557   # remove all processes that we know belong to other sessions. We use
558   # "sort | uniq -u" to do what amounts to a "set subtraction operation".
559   pids=$({ ls -id1 /proc/*/root/. 2>/dev/null |
560          sed -e 's,^[^0-9]*'$i'.*/\([1-9][0-9]*\)/.*$,\1,
561                  t
562                  d';
563          echo "${other_pids}";
564          echo "${other_pids}"; } | sort | uniq -u) >/dev/null 2>&1
565   # Kill all processes that are still left running in the session. This is
566   # typically an assortment of daemon processes that were started
567   # automatically. They result in us being unable to tear down the session
568   # cleanly.
569   [ -z "${pids}" ] && break
570   for j in $pids; do
571     # Unfortunately, the way that schroot sets up sessions has the
572     # side-effect of being unable to tell one session apart from another.
573     # This can result in us attempting to kill processes in other sessions.
574     # We make a best-effort to avoid doing so.
575     k="$( ( xargs -0 -n1 </proc/$j/environ ) 2>/dev/null |
576          sed 's/^CHROOT_SESSION_ID=/x/;t1;d;:1;q')"
577     if [ -n "${k}" -a "${k#x}" != "${session}" ]; then
578       other_pids="${other_pids}
579 ${j}"
580       continue
581     fi
582     kill -9 $pids
583   done
584 done
585 # End the chroot session. This should clean up all temporary files. But if we
586 # earlier failed to terminate all (daemon) processes inside of the session,
587 # deleting the session could fail. When that happens, the user has to manually
588 # clean up the stale files by invoking us with "--clean" after having killed
589 # all running processes.
590 schroot -c "${session}" -e
591 # Since no goma processes are running, we can remove goma directory.
592 rm -rf "$GOMA_TMP_DIR"
593 exit $rc
594 EOF
595 sudo chown root:root /usr/local/bin/"${target%bit}"
596 sudo chmod 755 /usr/local/bin/"${target%bit}"
597
598 # Add the standard Ubuntu update repositories if requested.
599 [ "${alt_repos}" = "y" -a \
600   -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
601 sudo sed -i '/^deb .* [^ -]\+ main$/p
602              s/^\(deb .* [^ -]\+\) main/\1-security main/
603              p
604              t1
605              d
606              :1;s/-security main/-updates main/
607              t
608              d' "/var/lib/chroot/${target}/etc/apt/sources.list"
609
610 # Add a few more repositories to the chroot
611 [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
612 sudo sed -i 's/ main$/ main restricted universe multiverse/' \
613          "/var/lib/chroot/${target}/etc/apt/sources.list"
614
615 # Add the Ubuntu "partner" repository, if available
616 if [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
617    HEAD "http://archive.canonical.com/ubuntu/dists/${distname}/partner" \
618    >&/dev/null; then
619   sudo sh -c '
620     echo "deb http://archive.canonical.com/ubuntu" \
621          "'"${distname}"' partner" \
622       >>"/var/lib/chroot/'"${target}"'/etc/apt/sources.list"'
623 fi
624
625 # Add source repositories, if the user requested we do so
626 [ "${add_srcs}" = "y" -a \
627   -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
628 sudo sed -i '/^deb[^-]/p
629              s/^deb\([^-]\)/deb-src\1/' \
630          "/var/lib/chroot/${target}/etc/apt/sources.list"
631
632 # Set apt proxy if host has set http_proxy
633 if [ -n "${http_proxy}" ]; then
634   sudo sh -c '
635     echo "Acquire::http::proxy \"'"${http_proxy}"'\";" \
636         >>"/var/lib/chroot/'"${target}"'/etc/apt/apt.conf"'
637 fi
638
639 # Update packages
640 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
641   apt-get update; apt-get -y dist-upgrade' || :
642
643 # Install a couple of missing packages
644 for i in debian-keyring ubuntu-keyring locales sudo; do
645   [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
646     sudo "/usr/local/bin/${target%bit}" apt-get -y install "$i" || :
647 done
648
649 # Configure locales
650 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
651   l='"${LANG:-en_US}"'; l="${l%%.*}"
652   [ -r /etc/locale.gen ] &&
653     sed -i "s/^# \($l\)/\1/" /etc/locale.gen
654   locale-gen $LANG en_US en_US.UTF-8' || :
655
656 # Enable multi-arch support, if available
657 sudo "/usr/local/bin/${target%bit}" dpkg --assert-multi-arch >&/dev/null &&
658   [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && {
659   sudo sed -i 's/ / [arch=amd64,i386] /' \
660               "/var/lib/chroot/${target}/etc/apt/sources.list"
661   [ -d /var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/ ] &&
662   sudo "/usr/local/bin/${target%bit}" dpkg --add-architecture \
663       $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) >&/dev/null ||
664     echo foreign-architecture \
665         $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) |
666       sudo sh -c \
667         "cat >'/var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/multiarch'"
668 }
669
670 # Configure "sudo" package
671 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
672   egrep -qs '"'^$(id -nu) '"' /etc/sudoers ||
673   echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'
674
675 # Install a few more commonly used packages
676 sudo "/usr/local/bin/${target%bit}" apt-get -y install                         \
677   autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool     \
678   lsof strace
679
680 # If running a 32bit environment on a 64bit machine, install a few binaries
681 # as 64bit. This is only done automatically if the chroot distro is the same as
682 # the host, otherwise there might be incompatibilities in build settings or
683 # runtime dependencies. The user can force it with the '-c' flag.
684 host_distro=$(grep -s DISTRIB_CODENAME /etc/lsb-release | \
685   cut -d "=" -f 2)
686 if [ "${copy_64}" = "y" -o \
687     "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \
688     file /bin/bash 2>/dev/null | grep -q x86-64; then
689   readlinepkg=$(sudo "/usr/local/bin/${target%bit}" sh -c \
690     'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1')
691   sudo "/usr/local/bin/${target%bit}" apt-get -y install                       \
692     lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1 lib64stdc++6
693   dep=
694   for i in binutils gdb; do
695     [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
696   done
697   [ -n "$dep" ] && sudo apt-get -y install $dep
698   sudo mkdir -p "/var/lib/chroot/${target}/usr/local/lib/amd64"
699   for i in libbfd libpython; do
700     lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
701            grep -s "$i" | awk '{ print $3 }')"
702     if [ -n "$lib" -a -r "$lib" ]; then
703       sudo cp "$lib" "/var/lib/chroot/${target}/usr/local/lib/amd64"
704     fi
705   done
706   for lib in libssl libcrypt; do
707     for path in /usr/lib /usr/lib/x86_64-linux-gnu; do
708       sudo cp $path/$lib* \
709               "/var/lib/chroot/${target}/usr/local/lib/amd64/" >&/dev/null || :
710     done
711   done
712   for i in gdb ld; do
713     sudo cp /usr/bin/$i "/var/lib/chroot/${target}/usr/local/lib/amd64/"
714     sudo sh -c "cat >'/var/lib/chroot/${target}/usr/local/bin/$i'" <<EOF
715 #!/bin/sh
716 exec /lib64/ld-linux-x86-64.so.2 --library-path /usr/local/lib/amd64 \
717   /usr/local/lib/amd64/$i "\$@"
718 EOF
719     sudo chmod 755 "/var/lib/chroot/${target}/usr/local/bin/$i"
720   done
721 fi
722
723
724 # If the install-build-deps.sh script can be found, offer to run it now
725 script="$(dirname $(readlink -f "$0"))/install-build-deps.sh"
726 if [ -x "${script}" ]; then
727   while :; do
728     echo
729     echo "If you plan on building Chrome inside of the new chroot environment,"
730     echo "you now have to install the build dependencies. Do you want me to"
731     printf "start the script that does this for you (y/n)? "
732     read install_deps
733     case "${install_deps}" in
734       y|Y)
735         echo
736         # We prefer running the script in-place, but this might not be
737         # possible, if it lives on a network filesystem that denies
738         # access to root.
739         tmp_script=
740         if ! sudo /usr/local/bin/"${target%bit}" \
741             sh -c "[ -x '${script}' ]" >&/dev/null; then
742           tmp_script="/tmp/${script##*/}"
743           cp "${script}" "${tmp_script}"
744         fi
745         # Some distributions automatically start an instance of the system-
746         # wide dbus daemon, cron daemon or of the logging daemon, when
747         # installing the Chrome build depencies. This prevents the chroot
748         # session from being closed.  So, we always try to shut down any running
749         # instance of dbus and rsyslog.
750         sudo /usr/local/bin/"${target%bit}" sh -c "${script};
751               rc=$?;
752               /etc/init.d/cron stop >/dev/null 2>&1 || :;
753               /etc/init.d/rsyslog stop >/dev/null 2>&1 || :;
754               /etc/init.d/dbus stop >/dev/null 2>&1 || :;
755               exit $rc"
756         rc=$?
757         [ -n "${tmp_script}" ] && rm -f "${tmp_script}"
758         [ $rc -ne 0 ] && exit $rc
759         break
760       ;;
761       n|N)
762         break
763       ;;
764     esac
765   done
766   echo
767 fi
768
769 # Check whether ~/chroot is on a (slow) network file system and offer to
770 # relocate it. Also offer relocation, if the user appears to have multiple
771 # spindles (as indicated by "${bind_mount}" being non-empty).
772 # We only offer this option, if it doesn't look as if a chroot environment
773 # is currently active. Otherwise, relocation is unlikely to work and it
774 # can be difficult for the user to recover from the failed attempt to relocate
775 # the ~/chroot directory.
776 # We don't aim to solve this problem for every configuration,
777 # but try to help with the common cases. For more advanced configuration
778 # options, the user can always manually adjust things.
779 mkdir -p "${HOME}/chroot/"
780 if [ ! -h "${HOME}/chroot" ] &&
781    ! egrep -qs '^[^[:space:]]*/chroot' /etc/fstab &&
782    { [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] ||
783      is_network_drive "${HOME}/chroot"; } &&
784    ! egrep -qs '/var/lib/[^/]*chroot/.*/chroot' /proc/mounts; then
785   echo "${HOME}/chroot is currently located on the same device as your"
786   echo "home directory."
787   echo "This might not be what you want. Do you want me to move it somewhere"
788   echo "else?"
789   # If the computer has multiple spindles, many users configure all or part of
790   # the secondary hard disk to be writable by the primary user of this machine.
791   # Make some reasonable effort to detect this type of configuration and
792   # then offer a good location for where to put the ~/chroot directory.
793   suggest=
794   for i in $(echo "${bind_mounts}"|cut -d ' ' -f 1); do
795     if [ -d "$i" -a -w "$i" -a \( ! -a "$i/chroot" -o -w "$i/chroot/." \) ] &&
796        ! is_network_drive "$i"; then
797       suggest="$i"
798     else
799       for j in "$i/"*; do
800         if [ -d "$j" -a -w "$j" -a \
801              \( ! -a "$j/chroot" -o -w "$j/chroot/." \) ] &&
802            ! is_network_drive "$j"; then
803           suggest="$j"
804         else
805           for k in "$j/"*; do
806             if [ -d "$k" -a -w "$k" -a \
807                  \( ! -a "$k/chroot" -o -w "$k/chroot/." \) ] &&
808                ! is_network_drive "$k"; then
809               suggest="$k"
810               break
811             fi
812           done
813         fi
814         [ -n "${suggest}" ] && break
815       done
816     fi
817     [ -n "${suggest}" ] && break
818   done
819   def_suggest="${HOME}"
820   if [ -n "${suggest}" ]; then
821     # For home directories that reside on network drives, make our suggestion
822     # the default option. For home directories that reside on a local drive,
823     # require that the user manually enters the new location.
824     if is_network_drive "${HOME}"; then
825       def_suggest="${suggest}"
826     else
827       echo "A good location would probably be in \"${suggest}\""
828     fi
829   fi
830   while :; do
831     printf "Physical location [${def_suggest}]: "
832     read dir
833     [ -z "${dir}" ] && dir="${def_suggest}"
834     [ "${dir%%/}" == "${HOME%%/}" ] && break
835     if ! [ -d "${dir}" -a -w "${dir}" ] ||
836        [ -a "${dir}/chroot" -a ! -w "${dir}/chroot/." ]; then
837       echo "Cannot write to ${dir}/chroot. Please try again"
838     else
839       mv "${HOME}/chroot" "${dir}/chroot"
840       ln -s "${dir}/chroot" "${HOME}/chroot"
841       for i in $(list_all_chroots); do
842         sudo "$i" mkdir -p "${dir}/chroot"
843       done
844       sudo sed -i "s,${HOME}/chroot,${dir}/chroot,g" /etc/schroot/mount-*
845       break
846     fi
847   done
848 fi
849
850 # Clean up package files
851 sudo schroot -c "${target%bit}" -p -- apt-get clean
852 sudo apt-get clean
853
854 trap '' INT TERM QUIT HUP
855 trap '' EXIT
856
857 # Let the user know what we did
858 cat <<EOF
859
860
861 Successfully installed ${distname} ${arch}
862
863 You can run programs inside of the chroot by invoking the
864 "/usr/local/bin/${target%bit}" command.
865
866 This command can be used with arguments, in order to just run a single
867 program inside of the chroot environment (e.g. "${target%bit} make chrome")
868 or without arguments, in order to run an interactive shell session inside
869 of the chroot environment.
870
871 If you need to run things as "root", you can use "sudo" (e.g. try
872 "sudo ${target%bit} apt-get update").
873
874 Your home directory is shared between the host and the chroot. But I
875 configured "${HOME}/chroot" to be private to the chroot environment.
876 You can use it for files that need to differ between environments. This
877 would be a good place to store binaries that you have built from your
878 source files.
879
880 For Chrome, this probably means you want to make your "out" directory a
881 symbolic link that points somewhere inside of "${HOME}/chroot".
882
883 You still need to run "gclient runhooks" whenever you switch from building
884 outside of the chroot to inside of the chroot. But you will find that you
885 don't have to repeatedly erase and then completely rebuild all your object
886 and binary files.
887
888 EOF