tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

install-chroot.sh (31054B)


      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 if [ $# -eq 0 ]; then
    538  # Run an interactive shell session
    539  schroot -c "${session}" -r -p
    540 else
    541  # Run a command inside of the chroot environment
    542  p="$1"; shift
    543  schroot -c "${session}" -r -p "$p" -- "$@"
    544 fi
    545 rc=$?
    546 
    547 # Compute the inode of the root directory inside of the chroot environment.
    548 i=$(schroot -c "${session}" -r -p ls -- -id /proc/self/root/. |
    549     awk '{ print $1 }') 2>/dev/null
    550 other_pids=
    551 while [ -n "$i" ]; do
    552  # Identify processes by the inode number of their root directory. Then
    553  # remove all processes that we know belong to other sessions. We use
    554  # "sort | uniq -u" to do what amounts to a "set subtraction operation".
    555  pids=$({ ls -id1 /proc/*/root/. 2>/dev/null |
    556         sed -e 's,^[^0-9]*'$i'.*/\([1-9][0-9]*\)/.*$,\1,
    557                 t
    558                 d';
    559         echo "${other_pids}";
    560         echo "${other_pids}"; } | sort | uniq -u) >/dev/null 2>&1
    561  # Kill all processes that are still left running in the session. This is
    562  # typically an assortment of daemon processes that were started
    563  # automatically. They result in us being unable to tear down the session
    564  # cleanly.
    565  [ -z "${pids}" ] && break
    566  for j in $pids; do
    567    # Unfortunately, the way that schroot sets up sessions has the
    568    # side-effect of being unable to tell one session apart from another.
    569    # This can result in us attempting to kill processes in other sessions.
    570    # We make a best-effort to avoid doing so.
    571    k="$( ( xargs -0 -n1 </proc/$j/environ ) 2>/dev/null |
    572         sed 's/^CHROOT_SESSION_ID=/x/;t1;d;:1;q')"
    573    if [ -n "${k}" -a "${k#x}" != "${session}" ]; then
    574      other_pids="${other_pids}
    575 ${j}"
    576      continue
    577    fi
    578    kill -9 $pids
    579  done
    580 done
    581 # End the chroot session. This should clean up all temporary files. But if we
    582 # earlier failed to terminate all (daemon) processes inside of the session,
    583 # deleting the session could fail. When that happens, the user has to manually
    584 # clean up the stale files by invoking us with "--clean" after having killed
    585 # all running processes.
    586 schroot -c "${session}" -e
    587 exit $rc
    588 EOF
    589 sudo chown root:root /usr/local/bin/"${target%bit}"
    590 sudo chmod 755 /usr/local/bin/"${target%bit}"
    591 
    592 # Add the standard Ubuntu update repositories if requested.
    593 [ "${alt_repos}" = "y" -a \
    594  -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
    595 sudo sed -i '/^deb .* [^ -]\+ main$/p
    596             s/^\(deb .* [^ -]\+\) main/\1-security main/
    597             p
    598             t1
    599             d
    600             :1;s/-security main/-updates main/
    601             t
    602             d' "/var/lib/chroot/${target}/etc/apt/sources.list"
    603 
    604 # Add a few more repositories to the chroot
    605 [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
    606 sudo sed -i 's/ main$/ main restricted universe multiverse/' \
    607         "/var/lib/chroot/${target}/etc/apt/sources.list"
    608 
    609 # Add the Ubuntu "partner" repository, if available
    610 if [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
    611   HEAD "http://archive.canonical.com/ubuntu/dists/${distname}/partner" \
    612   >&/dev/null; then
    613  sudo sh -c '
    614    echo "deb http://archive.canonical.com/ubuntu" \
    615         "'"${distname}"' partner" \
    616      >>"/var/lib/chroot/'"${target}"'/etc/apt/sources.list"'
    617 fi
    618 
    619 # Add source repositories, if the user requested we do so
    620 [ "${add_srcs}" = "y" -a \
    621  -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
    622 sudo sed -i '/^deb[^-]/p
    623             s/^deb\([^-]\)/deb-src\1/' \
    624         "/var/lib/chroot/${target}/etc/apt/sources.list"
    625 
    626 # Set apt proxy if host has set http_proxy
    627 if [ -n "${http_proxy}" ]; then
    628  sudo sh -c '
    629    echo "Acquire::http::proxy \"'"${http_proxy}"'\";" \
    630        >>"/var/lib/chroot/'"${target}"'/etc/apt/apt.conf"'
    631 fi
    632 
    633 # Update packages
    634 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
    635  apt-get update; apt-get -y dist-upgrade' || :
    636 
    637 # Install a couple of missing packages
    638 for i in debian-keyring ubuntu-keyring locales sudo; do
    639  [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
    640    sudo "/usr/local/bin/${target%bit}" apt-get -y install "$i" || :
    641 done
    642 
    643 # Configure locales
    644 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
    645  l='"${LANG:-en_US}"'; l="${l%%.*}"
    646  [ -r /etc/locale.gen ] &&
    647    sed -i "s/^# \($l\)/\1/" /etc/locale.gen
    648  locale-gen $LANG en_US en_US.UTF-8' || :
    649 
    650 # Enable multi-arch support, if available
    651 sudo "/usr/local/bin/${target%bit}" dpkg --assert-multi-arch >&/dev/null &&
    652  [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && {
    653  sudo sed -i 's/ / [arch=amd64,i386] /' \
    654              "/var/lib/chroot/${target}/etc/apt/sources.list"
    655  [ -d /var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/ ] &&
    656  sudo "/usr/local/bin/${target%bit}" dpkg --add-architecture \
    657      $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) >&/dev/null ||
    658    echo foreign-architecture \
    659        $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) |
    660      sudo sh -c \
    661        "cat >'/var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/multiarch'"
    662 }
    663 
    664 # Configure "sudo" package
    665 sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
    666  egrep -qs '"'^$(id -nu) '"' /etc/sudoers ||
    667  echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'
    668 
    669 # Install a few more commonly used packages
    670 sudo "/usr/local/bin/${target%bit}" apt-get -y install                         \
    671  autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool     \
    672  lsof strace
    673 
    674 # If running a 32bit environment on a 64bit machine, install a few binaries
    675 # as 64bit. This is only done automatically if the chroot distro is the same as
    676 # the host, otherwise there might be incompatibilities in build settings or
    677 # runtime dependencies. The user can force it with the '-c' flag.
    678 host_distro=$(grep -s DISTRIB_CODENAME /etc/lsb-release | \
    679  cut -d "=" -f 2)
    680 if [ "${copy_64}" = "y" -o \
    681    "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \
    682    file /bin/bash 2>/dev/null | grep -q x86-64; then
    683  readlinepkg=$(sudo "/usr/local/bin/${target%bit}" sh -c \
    684    'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1')
    685  sudo "/usr/local/bin/${target%bit}" apt-get -y install                       \
    686    lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1 lib64stdc++6
    687  dep=
    688  for i in binutils gdb; do
    689    [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
    690  done
    691  [ -n "$dep" ] && sudo apt-get -y install $dep
    692  sudo mkdir -p "/var/lib/chroot/${target}/usr/local/lib/amd64"
    693  for i in libbfd libpython; do
    694    lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
    695           grep -s "$i" | awk '{ print $3 }')"
    696    if [ -n "$lib" -a -r "$lib" ]; then
    697      sudo cp "$lib" "/var/lib/chroot/${target}/usr/local/lib/amd64"
    698    fi
    699  done
    700  for lib in libssl libcrypt; do
    701    for path in /usr/lib /usr/lib/x86_64-linux-gnu; do
    702      sudo cp $path/$lib* \
    703              "/var/lib/chroot/${target}/usr/local/lib/amd64/" >&/dev/null || :
    704    done
    705  done
    706  for i in gdb ld; do
    707    sudo cp /usr/bin/$i "/var/lib/chroot/${target}/usr/local/lib/amd64/"
    708    sudo sh -c "cat >'/var/lib/chroot/${target}/usr/local/bin/$i'" <<EOF
    709 #!/bin/sh
    710 exec /lib64/ld-linux-x86-64.so.2 --library-path /usr/local/lib/amd64 \
    711  /usr/local/lib/amd64/$i "\$@"
    712 EOF
    713    sudo chmod 755 "/var/lib/chroot/${target}/usr/local/bin/$i"
    714  done
    715 fi
    716 
    717 
    718 # If the install-build-deps.sh script can be found, offer to run it now
    719 script="$(dirname $(readlink -f "$0"))/install-build-deps.sh"
    720 if [ -x "${script}" ]; then
    721  while :; do
    722    echo
    723    echo "If you plan on building Chrome inside of the new chroot environment,"
    724    echo "you now have to install the build dependencies. Do you want me to"
    725    printf "start the script that does this for you (y/n)? "
    726    read install_deps
    727    case "${install_deps}" in
    728      y|Y)
    729        echo
    730        # We prefer running the script in-place, but this might not be
    731        # possible, if it lives on a network filesystem that denies
    732        # access to root.
    733        tmp_script=
    734        if ! sudo /usr/local/bin/"${target%bit}" \
    735            sh -c "[ -x '${script}' ]" >&/dev/null; then
    736          tmp_script="/tmp/${script##*/}"
    737          cp "${script}" "${tmp_script}"
    738        fi
    739        # Some distributions automatically start an instance of the system-
    740        # wide dbus daemon, cron daemon or of the logging daemon, when
    741        # installing the Chrome build depencies. This prevents the chroot
    742        # session from being closed.  So, we always try to shut down any running
    743        # instance of dbus and rsyslog.
    744        sudo /usr/local/bin/"${target%bit}" sh -c "${script};
    745              rc=$?;
    746              /etc/init.d/cron stop >/dev/null 2>&1 || :;
    747              /etc/init.d/rsyslog stop >/dev/null 2>&1 || :;
    748              /etc/init.d/dbus stop >/dev/null 2>&1 || :;
    749              exit $rc"
    750        rc=$?
    751        [ -n "${tmp_script}" ] && rm -f "${tmp_script}"
    752        [ $rc -ne 0 ] && exit $rc
    753        break
    754      ;;
    755      n|N)
    756        break
    757      ;;
    758    esac
    759  done
    760  echo
    761 fi
    762 
    763 # Check whether ~/chroot is on a (slow) network file system and offer to
    764 # relocate it. Also offer relocation, if the user appears to have multiple
    765 # spindles (as indicated by "${bind_mount}" being non-empty).
    766 # We only offer this option, if it doesn't look as if a chroot environment
    767 # is currently active. Otherwise, relocation is unlikely to work and it
    768 # can be difficult for the user to recover from the failed attempt to relocate
    769 # the ~/chroot directory.
    770 # We don't aim to solve this problem for every configuration,
    771 # but try to help with the common cases. For more advanced configuration
    772 # options, the user can always manually adjust things.
    773 mkdir -p "${HOME}/chroot/"
    774 if [ ! -h "${HOME}/chroot" ] &&
    775   ! egrep -qs '^[^[:space:]]*/chroot' /etc/fstab &&
    776   { [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] ||
    777     is_network_drive "${HOME}/chroot"; } &&
    778   ! egrep -qs '/var/lib/[^/]*chroot/.*/chroot' /proc/mounts; then
    779  echo "${HOME}/chroot is currently located on the same device as your"
    780  echo "home directory."
    781  echo "This might not be what you want. Do you want me to move it somewhere"
    782  echo "else?"
    783  # If the computer has multiple spindles, many users configure all or part of
    784  # the secondary hard disk to be writable by the primary user of this machine.
    785  # Make some reasonable effort to detect this type of configuration and
    786  # then offer a good location for where to put the ~/chroot directory.
    787  suggest=
    788  for i in $(echo "${bind_mounts}"|cut -d ' ' -f 1); do
    789    if [ -d "$i" -a -w "$i" -a \( ! -a "$i/chroot" -o -w "$i/chroot/." \) ] &&
    790       ! is_network_drive "$i"; then
    791      suggest="$i"
    792    else
    793      for j in "$i/"*; do
    794        if [ -d "$j" -a -w "$j" -a \
    795             \( ! -a "$j/chroot" -o -w "$j/chroot/." \) ] &&
    796           ! is_network_drive "$j"; then
    797          suggest="$j"
    798        else
    799          for k in "$j/"*; do
    800            if [ -d "$k" -a -w "$k" -a \
    801                 \( ! -a "$k/chroot" -o -w "$k/chroot/." \) ] &&
    802               ! is_network_drive "$k"; then
    803              suggest="$k"
    804              break
    805            fi
    806          done
    807        fi
    808        [ -n "${suggest}" ] && break
    809      done
    810    fi
    811    [ -n "${suggest}" ] && break
    812  done
    813  def_suggest="${HOME}"
    814  if [ -n "${suggest}" ]; then
    815    # For home directories that reside on network drives, make our suggestion
    816    # the default option. For home directories that reside on a local drive,
    817    # require that the user manually enters the new location.
    818    if is_network_drive "${HOME}"; then
    819      def_suggest="${suggest}"
    820    else
    821      echo "A good location would probably be in \"${suggest}\""
    822    fi
    823  fi
    824  while :; do
    825    printf "Physical location [${def_suggest}]: "
    826    read dir
    827    [ -z "${dir}" ] && dir="${def_suggest}"
    828    [ "${dir%%/}" == "${HOME%%/}" ] && break
    829    if ! [ -d "${dir}" -a -w "${dir}" ] ||
    830       [ -a "${dir}/chroot" -a ! -w "${dir}/chroot/." ]; then
    831      echo "Cannot write to ${dir}/chroot. Please try again"
    832    else
    833      mv "${HOME}/chroot" "${dir}/chroot"
    834      ln -s "${dir}/chroot" "${HOME}/chroot"
    835      for i in $(list_all_chroots); do
    836        sudo "$i" mkdir -p "${dir}/chroot"
    837      done
    838      sudo sed -i "s,${HOME}/chroot,${dir}/chroot,g" /etc/schroot/mount-*
    839      break
    840    fi
    841  done
    842 fi
    843 
    844 # Clean up package files
    845 sudo schroot -c "${target%bit}" -p -- apt-get clean
    846 sudo apt-get clean
    847 
    848 trap '' INT TERM QUIT HUP
    849 trap '' EXIT
    850 
    851 # Let the user know what we did
    852 cat <<EOF
    853 
    854 
    855 Successfully installed ${distname} ${arch}
    856 
    857 You can run programs inside of the chroot by invoking the
    858 "/usr/local/bin/${target%bit}" command.
    859 
    860 This command can be used with arguments, in order to just run a single
    861 program inside of the chroot environment (e.g. "${target%bit} make chrome")
    862 or without arguments, in order to run an interactive shell session inside
    863 of the chroot environment.
    864 
    865 If you need to run things as "root", you can use "sudo" (e.g. try
    866 "sudo ${target%bit} apt-get update").
    867 
    868 Your home directory is shared between the host and the chroot. But I
    869 configured "${HOME}/chroot" to be private to the chroot environment.
    870 You can use it for files that need to differ between environments. This
    871 would be a good place to store binaries that you have built from your
    872 source files.
    873 
    874 For Chrome, this probably means you want to make your "out" directory a
    875 symbolic link that points somewhere inside of "${HOME}/chroot".
    876 
    877 You still need to run "gclient runhooks" whenever you switch from building
    878 outside of the chroot to inside of the chroot. But you will find that you
    879 don't have to repeatedly erase and then completely rebuild all your object
    880 and binary files.
    881 
    882 EOF