목차

common.sh 분석

이 문서는 크로미움 OS 빌드 중 사용되는 common.sh 스크립트를 분석해 둔 것입니다.
common.sh 스크립트의 원본 전체를 보시려면 http://codesearch.google.com/을 참고하세요.

분석

# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
 
# Common constants for build scripts
## 빌드 스크립트들이 공통적으로 사용하는 상수들을 갖고 있습니다.
# This must evaluate properly for both /bin/bash and /bin/sh
## 이것은 반드시 /bin/bash와 /bin/sh에 대해 제대로 평가해야 합니다.
 
# All scripts should die on error unless commands are specifically excepted
# by prefixing with '!' or surrounded by 'set +e' / 'set -e'.
# TODO: Re-enable this once shflags is less prone to dying.
## 모든 스크립트들은 에러가 발생하면 종료되어야 합니다. 그렇지만 특별히 '!' 접두사가 붙어있거나
## 'set +e'와 'set -e'로 둘러쌓여 있는 경우에는 종료되지 않습니다.
## TODO: shflags가 종료되는 경우가 줄어들면 아래의 주석 처리된 부분을 활성화시켜야 합니다.
#set -e

맨 처음의 주석 부분입니다.
common.sh 스크립트의 저작권과 간단한 개요가 적혀 있습니다.

# The number of jobs to pass to tools that can run in parallel (such as make
# and dpkg-buildpackage
## make나 dpkg-buildpackage와 같은 작업을 처리할 때 동시에 병렬로 처리 가능한 수입니다. 
NUM_JOBS=$(grep -c "^processor" /proc/cpuinfo)

동시에 병렬 처리 가능한 갯수를 구해옵니다.
일반적으로 cpu의 코어 갯수를 가져오게 되어 있습니다.

# True if we have the 'pv' utility - also set up COMMON_PV_CAT for convenience
## 만일 'pv' 유틸리티가 존재하지 않으면 참으로 설정해줍니다. 또한 COMMON_PV_CAT도 설정해줍니다.
COMMON_PV_OK=1
COMMON_PV_CAT=pv
pv -V >/dev/null 2>&1 || COMMON_PV_OK=0
if [ $COMMON_PV_OK -eq 0 ]; then
  COMMON_PV_CAT=cat
fi

pv라는 유틸리티1)를 실행해보고 없거나 실패하면 COMMON_PV_OK0으로 지정합니다.
그리고 COMMON_PV_OK0으로 지정되면 COMMON_PV_CATpv 대신 cat으로 바꾸어줍니다.

# Make sure we have the location and name of the calling script, using
# the current value if it is already set.
## 이 스크립트를 실행한 스크립트의 위치와 이름을 갖고옵니다. 만일 값이 이미 설정
## 되어있을 경우 해당 값을 그대로 사용합니다.
SCRIPT_LOCATION=${SCRIPT_LOCATION:-$(dirname "$(readlink -f "$0")")}
SCRIPT_NAME=${SCRIPT_NAME:-$(basename "$0")}

common.sh 스크립트를 실행한 스크립트의 이름과 위치를 갖고 옵니다.
이 부분이 실행되면 SCRIPT_LOCATION에는 해당 스크립트의 절대 경로2)가 저장되어 있고,
SCRIPT_NAME에는 해당 스크립트의 이름이 저장되어 있습니다.

# Detect whether we're inside a chroot or not
## 현재 chroot 환경에서 실행 중인지 체크합니다.
if [ -e /etc/debian_chroot ]
then
  INSIDE_CHROOT=1
else
  INSIDE_CHROOT=0
fi

chroot 환경에 접속할 경우, /etc/debian_chroot/라는 디렉터리가 존재하게 됩니다.
그 경로를 검사하여 chroot 환경에서 실행 중인지 판별합니다.

# Construct a list of possible locations for the source tree.  This list is
# based on various environment variables and globals that may have been set
# by the calling script.
## 소스 트리에 사용될 사용 가능한 위치들의 리스트를 출력합니다. 이 리스트는 다양한 환경 변수들과
## common.sh를 실행한 스크립트가 설정했을 수도 있는 전역 값들에 기반합니다. 
function get_gclient_root_list() {
  if [ $INSIDE_CHROOT -eq 1 ]; then
    echo "/home/${USER}/trunk"
 
    if [ -n "${SUDO_USER}" ]; then echo "/home/${SUDO_USER}/trunk"; fi
  fi
 
  if [ -n "${COMMON_SH}" ]; then echo "$(dirname "$COMMON_SH")/../.."; fi
  if [ -n "${BASH_SOURCE}" ]; then echo "$(dirname "$BASH_SOURCE")/../.."; fi
}

이 함수는 아래 조건에 맞는 값들을 출력합니다.


# Based on the list of possible source locations we set GCLIENT_ROOT if it is
# not already defined by looking for a src directory in each seach path
# location.  If we do not find a valid looking root we error out.
## GCLIENT_ROOT가 각각의 검색 경로에 포함되어 있는 소스 디렉토리를 찾는 것에 의해 이미
## 정의되어있지 않은 경우, 사용 가능한 소스 위치에 기반하여 GCLIENT_ROOT를 설정합니다.
function get_gclient_root() {
  if [ -n "${GCLIENT_ROOT}" ]; then
    return
  fi
 
  for path in $(get_gclient_root_list); do
    if [ -d "${path}/src" ]; then
      GCLIENT_ROOT=${path}
      break
    fi
  done
 
  if [ -z "${GCLIENT_ROOT}" ]; then
    # Using dash or sh, we don't know where we are.  $0 refers to the calling
    # script, not ourselves, so that doesn't help us.
    ## dash 또는 sh를 사용할 경우, 우리는 현재 경로를 알 수 없습니다. '$0'은 이 스크립트가
    ## 아닌 이 스크립트를 실행한 스크립트를 참조합니다. 따라서 '$0'은 도움이 되지 않습니다.
    echo "Unable to determine location for common.sh.  If you are sourcing"
    echo "common.sh from a script run via dash or sh, you must do it in the"
    echo "following way:"
    echo '  COMMON_SH="$(dirname "$0")/../../scripts/common.sh"'
    echo '  . "$COMMON_SH"'
    echo "where the first line is the relative path from your script to"
    echo "common.sh."
    exit 1
  fi
}

이 함수는 GCLIENT_ROOT 변수에 사용 가능한 소스 디렉터리를 저장해 줍니다.
이 함수가 실행되기 전에 이미 설정되어 있을 경우 변경사항 없이 리턴하고,
설정되어 있지 않을 경우 get_client_root_list 함수를 실행한 결과값들 중에서 사용 가능한 소스 디렉터리를 찾아 저장해줍니다.
만일 위 과정에서 사용 가능한 소스 디렉터리를 찾지 못했으면 에러 메시지를 출력하고 스크립트를 종료합니다.

# Find root of source tree
## 소스 트리의 루트를 찾습니다.
get_gclient_root

위에서 정의한 get_gclient_root 함수를 실행하여 소스 트리의 루트를 찾습니다.

# Canonicalize the directories for the root dir and the calling script.
# readlink is part of coreutils and should be present even in a bare chroot.
# This is better than just using
#     FOO = "$(cd $FOO ; pwd)"
# since that leaves symbolic links intact.
# Note that 'realpath' is equivalent to 'readlink -f'.
## GCLIENT_ROOT와 이 스크립트를 실행한 스크립트의 경로를 cononical path로 변환시킵니다.
## readlink는 coreutils의 일부로써, 있는 그대로의 chroot에서도 존재합니다.
## 이것은 심볼릭 링크가 그대로 유지되기 때문에 아래의 명령어를 실행하는 것보다 편리합니다.
##     FOO = "$(cd $FOO ; pwd)"
## Note: 'realpath'와 'readlink -f'는 서로 같습니다.
SCRIPT_LOCATION=$(readlink -f $SCRIPT_LOCATION)
GCLIENT_ROOT=$(readlink -f $GCLIENT_ROOT)

위에서 얻어왔던 GCLIENT_ROOTSCRIPT_LOCATION을 절대 경로6)로 변환해줍니다.

# Other directories should always be pathed down from GCLIENT_ROOT.
## 다른 디렉터리들 또한 GCLIENT_ROOT 하위에 존재합니다.
SRC_ROOT="$GCLIENT_ROOT/src"
SRC_INTERNAL="$GCLIENT_ROOT/src-internal"
SCRIPTS_DIR="$SRC_ROOT/scripts"

위에서 얻어온 경로들을 이용해 하위 세부 경로들을 가져옵니다.

# Load developer's custom settings.  Default location is in scripts dir,
# since that's available both inside and outside the chroot.  By convention,
# settings from this file are variables starting with 'CHROMEOS_'
## 개발자의 사용자 설정을 불러옵니다. 기본 경로는 chroot 내부는 물론 외부에서도
## 유효해야하기 때문에 scripts 디렉터리 안에 있습니다. 관례상 이 파일의 설정들은
## 'CHROMEOS_'로 시작하는 변수들입니다.
CHROMEOS_DEV_SETTINGS="${CHROMEOS_DEV_SETTINGS:-$SCRIPTS_DIR/.chromeos_dev}"
if [ -f $CHROMEOS_DEV_SETTINGS ]; then
  # Turn on exit-on-error during custom settings processing
  ## 사용자 설정이 진행중일 때 에러가 발생하면 종료되도록 설정해줍니다.
  SAVE_OPTS=$(set +o)
  set -e
 
  # Read settings
  ## 설정들을 읽습니다.
  . $CHROMEOS_DEV_SETTINGS
 
  # Restore previous state of exit-on-error
  ## 에러가 발생하면 종료하도록 한 것을 되돌립니다.
  eval "$SAVE_OPTS"
fi

개발자가 개별적으로 설정해놓은 사용자 설정을 불러옵니다.
이 설정 스크립트는 기본적으로 SCRIPTS_DIR 밑에 .chromeos_dev 파일로 존재하는데,
이는 사용자가 CHROMEOS_DEV_SETTINGS 변수를 미리 변경하는 것으로 변경해 줄 수 있습니다.
이 설정 스크립트를 실행하는 동안 에러가 발생하면 스크립트 실행이 종료됩니다.

# Load shflags
## shflags를 불러옵니다.
if [[크로미움_os:크로미움_os_구조_분석:소스:스크립트:f_usr_lib_shflags]]; then
  . /usr/lib/shflags
elif [ -f ./lib/shflags/shflags ]; then
  . ./lib/shflags/shflags
else
  . "${SRC_ROOT}/scripts/lib/shflags/shflags"
fi

shflags 스크립트가 존재하는 곳을 찾아 shflags 스크립트를 실행합니다.

# Our local mirror
## 구글의 로컬 미러 서버입니다.
DEFAULT_CHROMEOS_SERVER=${CHROMEOS_SERVER:-"http://build.chromium.org/mirror"}
 
# Upstream mirrors and build suites come in 2 flavors
#   DEV - development chroot, used to build the chromeos image
#   IMG - bootable image, to run on actual hardware
## Upsteam의 미러 서버들과 빌드 묶음들은 2가지 특성이 있습니다.
##   DEV - chroot에서의 개발, chromeos image 빌드에 사용된다.
##   IMG - 부팅 가능한 이미지, 실제 하드웨어에서 동작한다.
 
DEFAULT_DEV_MIRROR=${CHROMEOS_DEV_MIRROR:-"${DEFAULT_CHROMEOS_SERVER}/ubuntu"}
DEFAULT_DEV_SUITE=${CHROMEOS_DEV_SUITE:-"karmic"}
 
DEFAULT_IMG_MIRROR=${CHROMEOS_IMG_MIRROR:-"${DEFAULT_CHROMEOS_SERVER}/ubuntu"}
DEFAULT_IMG_SUITE=${CHROMEOS_IMG_SUITE:-"karmic"}

구글의 미러 서버 주소들을 설정해줍니다.
여기서 설정해준 주소가 사용되는 곳을 찾지 못했기에 일단 별도의 설명은 붙이지 않습니다.

# Default location for chroot
## chroot의 기본 경로입니다.
DEFAULT_CHROOT_DIR=${CHROMEOS_CHROOT_DIR:-"$GCLIENT_ROOT/chroot"}

chroot의 경로를 구해옵니다.

# All output files from build should go under $DEFAULT_BUILD_ROOT, so that
# they don't pollute the source directory.
## 빌드 중에 나온 모든 출력 파일들은 소스 디렉터리에 영향을 주지 않게 하기 위하여 
## DEFAULT_BUILD_ROOT 디렉터리로 들어가게 됩니다.
DEFAULT_BUILD_ROOT=${CHROMEOS_BUILD_ROOT:-"$SRC_ROOT/build"}

빌드된 결과물들이 출력될 경로를 지정해줍니다.
빌드된 이미지 또한 이 곳에 나타나게 됩니다.

# Set up a global ALL_BOARDS value
## 글로벌 변수인 ALL_BOARDS를 설정해줍니다.
if [ -d $SRC_ROOT/overlays ]; then
  ALL_BOARDS=$(cd $SRC_ROOT/overlays;ls -1d overlay-* 2>&-|sed 's,overlay-,,g')
fi
# Strip CR
## CR(Carriage return) 문자를 잘라냅니다.
ALL_BOARDS=$(echo $ALL_BOARDS)
# Set a default BOARD
## 기본 보드를 설정합니다.
#DEFAULT_BOARD=x86-generic # or...
DEFAULT_BOARD=$(echo $ALL_BOARDS | awk '{print $NF}')

이 부분을 실행하면 ALL_BOARDS 변수에 모든 보드의 이름이 저장됩니다.7)
그리고 DEFAULT_BOARD 변수에는 ALL_BOARDS의 첫 번째 값이 기본으로 저장됩니다.

# Enable --fast by default.
## --fast 속성을 활성화시킵니다.
DEFAULT_FAST=${FLAGS_TRUE}

--fast 속성을 활성화시킵니다.
이 속성이 활성화되어있으면 빌드 시 사용 가능한 모든 CPU 코어를 사용하여 빌드하기 때문에 빠른 빌드가 가능하도록 해 줍니다.

# Standard filenames
## 기본 파일 이름들을 정의합니다.
CHROMEOS_IMAGE_NAME="chromiumos_image.bin"
CHROMEOS_TEST_IMAGE_NAME="chromiumos_test_image.bin"
CHROMEOS_FACTORY_TEST_IMAGE_NAME="chromiumos_factory_image.bin"

크로미움 OS가 빌드된 후 출력될 결과물들의 이름을 정의해줍니다.

# Directory locations inside the dev chroot
## chroot 환경에서의 trunk 경로를 설정해줍니다.
CHROOT_TRUNK_DIR="/home/$USER/trunk"

chroot 환경에서는 /home/사용자계정/trunk 경로에 소스들이 존재합니다.
해당 경로를 설정해줍니다.

# Install make for portage ebuilds.  Used by build_image and gmergefs.
## portage의 ebuilds들에 사용될 make를 작성합니다.
## build_image와 gmergefs에서 사용됩니다.
# TODO: Is /usr/local/autotest-chrome still used by anyone?
## TODO: 아직도 /usr/local/autotest-chrome을 사용하는 분이 계신가요?
DEFAULT_INSTALL_MASK="
  *.a
  *.la
  /etc/init.d
  /etc/runlevels
  /lib/rc
  /usr/bin/Xnest
  /usr/bin/Xvfb
  /usr/include
  /usr/lib/debug
  /usr/lib/gcc
  /usr/lib/gtk-2.0/include
  /usr/lib/pkgconfig
  /usr/local/autotest
  /usr/local/autotest-chrome
  /usr/man
  /usr/share/aclocal
  /usr/share/doc
  /usr/share/gettext
  /usr/share/gtk-2.0
  /usr/share/gtk-doc
  /usr/share/info
  /usr/share/man
  /usr/share/openrc
  /usr/share/pkgconfig
  /usr/share/readline
  "
 
FACTORY_INSTALL_MASK="
  /opt/Qualcomm
  /opt/Synaptics
  /opt/google/chrome
  /opt/google/o3d
  /opt/google/talkplugin
  /opt/netscape
  /usr/lib/debug
  /usr/lib/dri
  /usr/lib/python2.6/test
  /usr/local/autotest
  /usr/local/autotest-chrome
  /usr/local/autotest-pkgs
  /usr/share/X11
  /usr/share/chewing
  /usr/share/fonts
  /usr/share/ibus-pinyin
  /usr/share/libhangul
  /usr/share/locale
  /usr/share/m17n
  /usr/share/mime
  /usr/share/sounds
  /usr/share/tts
  /usr/share/zoneinfo
  "

이 부분은 젠투의 portage 빌드 시스템에 대한 이해가 필요할 것 같습니다.
추측하건대 빌드할 때 사용되는 make 파일에 기본적으로 포함될 정보로 보입니다.
추후에 자세한 공부를 한 후에 내용을 정확하게 수정하겠습니다.

# Check to ensure not running old scripts
## 오래된 스크립트로 작동하고 있는 건 아닌지 체크합니다.
V_REVERSE=''
V_VIDOFF=''
case "$(basename $0)" in
  build_image.sh|build_platform_packages.sh|customize_rootfs.sh|make_chroot.sh)
  echo
  echo "$V_REVERSE============================================================"
  echo "===========================  WARNING  ======================"
  echo "============================================================$V_VIDOFF"
  echo
  echo "RUNNING OLD BUILD SYSTEM SCRIPTS. RUN THE PORTAGE-BASED BUILD HERE:"
  echo "http://www.chromium.org/chromium-os/building-chromium-os/portage-based-build"
  echo
  if [ "$USER" != "chrome-bot" ]; then
    read -n1 -p "Press any key to continue using the OLD build system..."
    echo
    echo
  fi
  ;;
esac

현재 오래된 스크립트로 작동하고 있는 지 확인합니다.
이를 확인하기 위해 이 스크립트를 실행한 스크립트의 파일명을 확인하는데,
만약 파일명이 build_image.sh, build_platform_packages.sh, customize_rootfs.sh, make_chroot.sh일 경우 오래된 스크립트를 사용하고 있음을 경고해줍니다.
또한 사용자계정이 chrome-bot8)이 아닐 경우, 사용자가 내용을 확인할 수 있도록 Press any key……를 출력해줍니다.
basename 명령어는 경로에서 파일 이름만 추출해서 출력해줍니다. 예를 들어

basename /home/borios/hello.cpp 

를 실행한다면 결과값으로는 hello.cpp가 출력됩니다.

남은 부분

# -----------------------------------------------------------------------------
# Functions
 
function setup_board_warning {
  echo
  echo "$V_REVERSE=================  WARNING  ======================$V_VIDOFF"
  echo
  echo "*** No default board detected in " \
    "$GCLIENT_ROOT/src/scripts/.default_board"
  echo "*** Either run setup_board with default flag set"
  echo "*** or echo |board_name| > $GCLIENT_ROOT/src/scripts/.default_board"
  echo
}
 
 
# Sets the default board variable for calling script
function get_default_board {
  DEFAULT_BOARD=
 
  if [ -f "$GCLIENT_ROOT/src/scripts/.default_board" ] ; then
    DEFAULT_BOARD=$(cat "$GCLIENT_ROOT/src/scripts/.default_board")
  fi
}
 
 
# Make a package
function make_pkg_common {
  # Positional parameters from calling script.  :? means "fail if unset".
  set -e
  PKG_BASE=${1:?}
  shift
  set +e
 
  # All packages are built in the chroot
  assert_inside_chroot
 
  # Command line options
  DEFINE_string build_root "$DEFAULT_BUILD_ROOT" "Root of build output"
 
  # Parse command line and update positional args
  FLAGS "$@" || exit 1
  eval set -- "${FLAGS_ARGV}"
 
  # Die on any errors
  set -e
 
  # Make output dir
  local out_dir="$FLAGS_build_root/x86/local_packages"
  mkdir -p "$out_dir"
 
  # Remove previous package from output dir
  rm -f "$out_dir"/${PKG_BASE}_*.deb
 
  # Rebuild the package
  pushd "$SCRIPT_LOCATION"
  rm -f ../${PKG_BASE}_*.deb
  dpkg-buildpackage -b -tc -us -uc -j$NUM_JOBS
  mv ../${PKG_BASE}_*.deb "$out_dir"
  rm ../${PKG_BASE}_*.changes
  popd
}
 
# Enter a chroot and restart the current script if needed
function restart_in_chroot_if_needed {
  # NB:  Pass in ARGV:  restart_in_chroot_if_needed "$@"
  if [ $INSIDE_CHROOT -ne 1 ]; then
    # Get inside_chroot path for script.
    local chroot_path="$(reinterpret_path_for_chroot "$0")"
    exec $SCRIPTS_DIR/enter_chroot.sh -- \
      "$chroot_path" "$@"
  fi
}
 
# Fail unless we're inside the chroot.  This guards against messing up your
# workstation.
function assert_inside_chroot {
  if [ $INSIDE_CHROOT -ne 1 ]; then
    echo "This script must be run inside the chroot.  Run this first:"
    echo "    $SCRIPTS_DIR/enter_chroot.sh"
    exit 1
  fi
}
 
# Fail if we're inside the chroot.  This guards against creating or entering
# nested chroots, among other potential problems.
function assert_outside_chroot {
  if [ $INSIDE_CHROOT -ne 0 ]; then
    echo "This script must be run outside the chroot."
    exit 1
  fi
}
 
function assert_not_root_user {
  if [ $(id -u) = 0 ]; then
    echo "This script must be run as a non-root user."
    exit 1
  fi
}
 
# Returns true if the input file is whitelisted.
#
# $1 - The file to check
is_whitelisted() {
  local file=$1
  local whitelist="$FLAGS_whitelist"
  test -f "$whitelist" || (echo "Whitelist file missing ($whitelist)" && exit 1)
 
  local checksum=$(md5sum "$file" | awk '{ print $1 }')
  local count=$(sed -e "s/#.*$//" "${whitelist}" | grep -c "$checksum" \
                || /bin/true)
  test $count -ne 0
}
 
# Check that all arguments are flags; that is, there are no remaining arguments
# after parsing from shflags.  Allow (with a warning) a single empty-string
# argument.
#
# TODO: fix buildbot so that it doesn't pass the empty-string parameter,
# then change this function.
#
# Usage: check_flags_only_and_allow_null_arg "$@" && set --
function check_flags_only_and_allow_null_arg {
  do_shift=1
  if [[ $# == 1 && -z "$@" ]]; then
    echo "$0: warning: ignoring null argument" >&2
    shift
    do_shift=0
  fi
  if [[ $# -gt 0 ]]; then
    echo "error: invalid arguments: \"$@\"" >&2
    flags_help
    exit 1
  fi
  return $do_shift
}
 
V_RED="\e[31m"
V_YELLOW="\e[33m"
V_BOLD_GREEN="\e[1;32m"
V_BOLD_RED="\e[1;31m"
V_BOLD_YELLOW="\e[1;33m"
 
function info {
  echo -e >&2  "${V_BOLD_GREEN}INFO    ${CROS_LOG_PREFIX:-""}: $1${V_VIDOFF}"
}
 
function warn {
  echo -e >&2 "${V_BOLD_YELLOW}WARNING ${CROS_LOG_PREFIX:-""}: $1${V_VIDOFF}"
}
 
function error {
  echo -e >&2    "${V_BOLD_RED}ERROR   ${CROS_LOG_PREFIX:-""}: $1${V_VIDOFF}"
}
 
function die {
  error "$1"
  exit 1
}
 
# Retry an emerge command according to $FLAGS_retries
# The $EMERGE_JOBS flags will only be added the first time the command is run
function eretry () {
  local i
  for i in $(seq $FLAGS_retries); do
    echo "Retrying $@"
    "$@" $EMERGE_JOBS && return 0
  done
  "$@" && return 0
  return 1
}
 
# Removes single quotes around parameter
# Arguments:
#   $1 - string which optionally has surrounding quotes
# Returns:
#   None, but prints the string without quotes.
function remove_quotes() {
  echo "$1" | sed -e "s/^'//; s/'$//"
}
 
# Writes stdin to the given file name as root using sudo in overwrite mode.
#
# $1 - The output file name.
function sudo_clobber() {
  sudo tee "$1" > /dev/null
}
 
# Writes stdin to the given file name as root using sudo in append mode.
#
# $1 - The output file name.
function sudo_append() {
  sudo tee -a "$1" > /dev/null
}
 
# Unmounts a directory, if the unmount fails, warn, and then lazily unmount.
#
# $1 - The path to unmount.
function safe_umount {
  path=${1:?}
  shift
 
  if ! sudo umount -d "${path}"; then
    warn "Failed to unmount ${path}"
    warn "Doing a lazy unmount"
 
    sudo umount -d -l "${path}" || die "Failed to lazily unmount ${path}"
  fi
}
 
# Fixes symlinks that are incorrectly prefixed with the build root ${1}
# rather than the real running root '/'.
# TODO(sosa) - Merge setup - cleanup below with this method.
fix_broken_symlinks() {
  local build_root="${1}"
  local symlinks=$(find "${build_root}/usr/local" -lname "${build_root}/*")
  local symlink
  for symlink in ${symlinks}; do
    echo "Fixing ${symlink}"
    local target=$(ls -l "${symlink}" | cut -f 2 -d '>')
    # Trim spaces from target (bashism).
    target=${target/ /}
    # Make new target (removes rootfs prefix).
    new_target=$(echo ${target} | sed "s#${build_root}##")
 
    echo "Fixing symlink ${symlink}"
    sudo unlink "${symlink}"
    sudo ln -sf "${new_target}" "${symlink}"
  done
}
 
# Sets up symlinks for the developer root. It is necessary to symlink
# usr and local since the developer root is mounted at /usr/local and
# applications expect to be installed under /usr/local/bin, etc.
# This avoids packages installing into /usr/local/usr/local/bin.
# ${1} specifies the symlink target for the developer root.
# ${2} specifies the symlink target for the var directory.
# ${3} specifies the location of the stateful partition.
setup_symlinks_on_root() {
  # Give args better names.
  local dev_image_target=${1}
  local var_target=${2}
  local dev_image_root="${3}/dev_image"
 
  # If our var target is actually the standard var, we are cleaning up the
  # symlinks (could also check for /usr/local for the dev_image_target).
  if [ ${var_target} = "/var" ]; then
    echo "Cleaning up /usr/local symlinks for ${dev_image_root}"
  else
    echo "Setting up symlinks for /usr/local for ${dev_image_root}"
  fi
 
  # Set up symlinks that should point to ${dev_image_target}.
  local path
  for path in usr local; do
    if [ -h "${dev_image_root}/${path}" ]; then
      sudo unlink "${dev_image_root}/${path}"
    elif [ -e "${dev_image_root}/${path}" ]; then
      die "${dev_image_root}/${path} should be a symlink if exists"
    fi
    sudo ln -s ${dev_image_target} "${dev_image_root}/${path}"
  done
 
  # Setup var symlink.
  if [ -h "${dev_image_root}/var" ]; then
    sudo unlink "${dev_image_root}/var"
  elif [ -e "${dev_image_root}/var" ]; then
    die "${dev_image_root}/var should be a symlink if it exists"
  fi
 
  sudo ln -s "${var_target}" "${dev_image_root}/var"
}
 
# These two helpers clobber the ro compat value in our root filesystem.
#
# When the system is built with --enable_rootfs_verification, bit-precise
# integrity checking is performed.  That precision poses a usability issue on
# systems that automount partitions with recognizable filesystems, such as
# ext2/3/4.  When the filesystem is mounted 'rw', ext2 metadata will be
# automatically updated even if no other writes are performed to the
# filesystem.  In addition, ext2+ does not support a "read-only" flag for a
# given filesystem.  That said, forward and backward compatibility of
# filesystem features are supported by tracking if a new feature breaks r/w or
# just write compatibility.  We abuse the read-only compatibility flag[1] in
# the filesystem header by setting the high order byte (le) to FF.  This tells
# the kernel that features R24-R31 are all enabled.  Since those features are
# undefined on all ext-based filesystem, all standard kernels will refuse to
# mount the filesystem as read-write -- only read-only[2].
#
# [1] 32-bit flag we are modifying:
#  http://git.chromium.org/cgi-bin/gitweb.cgi?p=kernel.git;a=blob;f=include/linux/ext2_fs.h#l417
# [2] Mount behavior is enforced here:
#  http://git.chromium.org/cgi-bin/gitweb.cgi?p=kernel.git;a=blob;f=fs/ext2/super.c#l857
#
# N.B., if the high order feature bits are used in the future, we will need to
#       revisit this technique.
disable_rw_mount() {
  local rootfs="$1"
  local offset="${2-0}"  # in bytes
  local ro_compat_offset=$((0x464 + 3))  # Set 'highest' byte
  printf '\377' |
    sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \
            conv=notrunc count=1 bs=1
}
 
enable_rw_mount() {
  local rootfs="$1"
  local offset="${2-0}"
  local ro_compat_offset=$((0x464 + 3))  # Set 'highest' byte
  printf '\000' |
    sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \
            conv=notrunc count=1 bs=1
}
 
# Get current timestamp. Assumes common.sh runs at startup.
start_time=$(date +%s)
 
# Print time elsapsed since start_time.
print_time_elapsed() {
  local end_time=$(date +%s)
  local elapsed_seconds=$(($end_time - $start_time))
  local minutes=$(($elapsed_seconds / 60))
  local seconds=$(($elapsed_seconds % 60))
  echo "Elapsed time: ${minutes}m${seconds}s"
}
 
# This function is a place to put code to incrementally update the
# chroot so that users don't need to fully re-make it.  It should
# be called from scripts that are run _outside_ the chroot.
#
# Please put date information so it's easy to keep track of when
# old hacks can be retired and so that people can detect when a
# hack triggered when it shouldn't have.
#
# ${1} specifies the location of the chroot.
chroot_hacks_from_outside() {
  # Give args better names.
  local chroot_dir=$1
 
  # Add root as a sudoer if not already done.
  if ! sudo grep -q '^root ALL=(ALL) ALL$' "${chroot_dir}/etc/sudoers" ; then
    info "Upgrading old chroot (pre 2010-10-19) - adding root to sudoers"
    sudo bash -c "echo root ALL=\(ALL\) ALL >> \"${chroot_dir}/etc/sudoers\""
  fi
}
 
# The board and variant command line options can be used in a number of ways
# to specify the board and variant.  The board can encode both pieces of
# information separated by underscores.  Or the variant can be passed using
# the separate variant option.  This function extracts the canonical board and
# variant information and provides it in the BOARD, VARIANT and BOARD_VARIANT
# variables.
get_board_and_variant() {
  local flags_board="${1}"
  local flags_variant="${2}"
 
  BOARD=$(echo "$flags_board" | cut -d '_' -f 1)
  VARIANT=${flags_variant:-$(echo "$flags_board" | cut -s -d '_' -f 2)}
 
  if [ -n "$VARIANT" ]; then
    BOARD_VARIANT="${BOARD}_${VARIANT}"
  else
    BOARD_VARIANT="${BOARD}"
  fi
}
 
# This function converts a chromiumos image into a test image, either
# in place or by copying to a new test image filename first. It honors
# the following flags (see mod_image_for_test.sh)
#
#   --factory
#   --factory_install
#   --force_copy
#
# On entry, pass the directory containing the image, and the image filename
# On exit, it puts the pathname of the resulting test image into
# CHROMEOS_RETURN_VAL
# (yes this is ugly, but perhaps less ugly than the alternatives)
#
# Usage:
#   SRC_IMAGE=$(prepare_test_image "directory" "imagefile")
prepare_test_image() {
  # If we're asked to modify the image for test, then let's make a copy and
  # modify that instead.
  # Check for manufacturing image.
  local args
 
  if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
    args="--factory"
  fi
 
  # Check for install shim.
  if [ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]; then
    args="--factory_install"
  fi
 
  # Check for forcing copy of image
  if [ ${FLAGS_force_copy} -eq ${FLAGS_TRUE} ]; then
    args="${args} --force_copy"
  fi
 
  # Modify the image for test, creating a new test image
  "${SCRIPTS_DIR}/mod_image_for_test.sh" --board=${FLAGS_board} \
    --image="$1/$2" --noinplace ${args}
 
  # From now on we use the just-created test image
  if [ ${FLAGS_factory} -eq ${FLAGS_TRUE} ]; then
    CHROMEOS_RETURN_VAL="$1/${CHROMEOS_FACTORY_TEST_IMAGE_NAME}"
  else
    CHROMEOS_RETURN_VAL="$1/${CHROMEOS_TEST_IMAGE_NAME}"
  fi
}
 
# Check that the specified file exists.  If the file path is empty or the file
# doesn't exist on the filesystem generate useful error messages.  Otherwise
# show the user the name and path of the file that will be used.  The padding
# parameter can be used to tabulate multiple name:path pairs.  For example:
#
# check_for_file "really long name" "...:" "file.foo"
# check_for_file "short name" ".........:" "another.bar"
#
# Results in the following output:
#
# Using really long name...: file.foo
# Using short name.........: another.bar
#
# If tabulation is not required then passing "" for padding generates the
# output "Using <name> <path>"
check_for_file() {
  local name=$1
  local padding=$2
  local path=$3
 
  if [ -z "${path}" ]; then
    die "No ${name} file specified."
  fi
 
  if [ ! -e "${path}" ]; then
    die "No ${name} file found at: ${path}"
  else
    info "Using ${name}${padding} ${path}"
  fi
}
 
# Check that the specified tool exists.  If it does not exist in the PATH
# generate a useful error message indicating how to install the ebuild
# that contains the required tool.
check_for_tool() {
  local tool=$1
  local ebuild=$2
 
  if ! which "${tool}" >/dev/null ; then
    error "The ${tool} utility was not found in your path.  Run the following"
    error "command in your chroot to install it: sudo -E emerge ${ebuild}"
    exit 1
  fi
}
 
# Reinterprets path from outside the chroot for use inside.
# Returns "" if "" given.
# $1 - The path to reinterpret.
function reinterpret_path_for_chroot() {
  if [ $INSIDE_CHROOT -ne 1 ]; then
    if [ -z "${1}" ]; then
      echo ""
    else
      local path_abs_path=$(readlink -f "${1}")
      local gclient_root_abs_path=$(readlink -f "${GCLIENT_ROOT}")
 
      # Strip the repository root from the path.
      local relative_path=$(echo ${path_abs_path} \
          | sed s:${gclient_root_abs_path}/::)
 
      if [ "${relative_path}" = "${path_abs_path}" ]; then
        die "Error reinterpreting path.  Path ${1} is not within source tree."
      fi
 
      # Prepend the chroot repository path.
      echo "/home/${USER}/trunk/${relative_path}"
    fi
  else
    # Path is already inside the chroot :).
    echo "${1}"
  fi
}
1)
파이프라인을 통해 데이터의 진행 상황을 볼 수 있도록 해 줍니다. 자세한 내용은 이 페이지를 참조하세요.
2)
cononical path를 말하는 것으로, 루트(/)로부터 시작되는 순수한 절대 경로를 말합니다.
3)
sudo 명령어를 사용할 때 이용되는 계정이 저장되어 있습니다.
4)
common.sh 스크립트의 경로가 저장되어 있습니다.
5)
아직 용도를 알아내지 못했습니다.
6)
이것 역시 canonical path를 말합니다.
7)
'BOARD1 BOARD2 BOARD3 …'와 같이 저장됩니다.
8)
자동 빌드 봇으로 추측됩니다.