diff --git a/chroot_version_hooks.d/45_rewrite_sudoers.d b/chroot_version_hooks.d/45_rewrite_sudoers.d index 316d434f3f..941a5948bd 100644 --- a/chroot_version_hooks.d/45_rewrite_sudoers.d +++ b/chroot_version_hooks.d/45_rewrite_sudoers.d @@ -5,11 +5,12 @@ # Note that this script is invoked by make_chroot in addition # to normal upgrade pathways. -if [ "$(id -u)" != 0 ]; then +if [ "${UID:-$(id -u)}" != 0 ]; then # Note that since we're screwing w/ sudo variables, this script # explicitly bounces up to root for everything it does- that way # if anyone introduces a temp depriving in the sudo setup, it can't break # mid upgrade. + load_environment_whitelist exec sudo bash -e "${VERSION_HOOKS_DIR}/45_rewrite_sudoers.d" \ / "${USER}" "${ENVIRONMENT_WHITELIST[@]}" exit 1 diff --git a/chroot_version_hooks.d/47_path_overrides b/chroot_version_hooks.d/47_path_overrides index 58f0dfbbe1..4ca0c6d8fb 100644 --- a/chroot_version_hooks.d/47_path_overrides +++ b/chroot_version_hooks.d/47_path_overrides @@ -2,12 +2,4 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Ensure that crosutils path overrides are in use; note that chroot -# creation also invokes this, thus why we check for CROS_CHROOT; for -# the normal upgrade pathway, it's non existant. For chroot creation, -# It points to the chroot base. -sudo mkdir -p "${CROS_CHROOT}/etc/profile.d/" -echo 'export PATH="/usr/local/path-overrides${PATH:+:${PATH}}"' | \ - sudo tee "${CROS_CHROOT}"/etc/profile.d/crosutils-path-overrides.sh \ - > /dev/null -sudo chmod 644 "${CROS_CHROOT}"/etc/profile.d/crosutils-path-overrides.sh +# Path overrides are no longer in use, so this script is just a placeholder. diff --git a/common.sh b/common.sh index e66b58056b..6c59ea07b0 100644 --- a/common.sh +++ b/common.sh @@ -209,6 +209,15 @@ get_gclient_root() { fi } +# Populate the ENVIRONMENT_WHITELIST array. +load_environment_whitelist() { + set -f + ENVIRONMENT_WHITELIST=( + $("${GCLIENT_ROOT}/chromite/scripts/cros_env_whitelist") + ) + set +f +} + # Find root of source tree get_gclient_root @@ -300,20 +309,6 @@ DEFAULT_FAST=${FLAGS_TRUE} # Directory to store built images. Should be set by sourcing script when used. BUILD_DIR= -# List of variables to proxy into the chroot from the host, and to -# have sudo export if existent. -# Anytime this list is modified, to make that change active a new -# chroot_version_hooks.d upgrade script that symlinks to 45_rewrite_sudoers.d -# is required. -ENVIRONMENT_WHITELIST=( - CHROMEOS_OFFICIAL - {http{,s},ftp,all,no}_proxy - RSYNC_PROXY - GIT_{PROXY_COMMAND,SSH} - SSH_AGENT_PID - SSH_AUTH_SOCK -) - # Standard filenames CHROMEOS_BASE_IMAGE_NAME="chromiumos_base_image.bin" CHROMEOS_IMAGE_NAME="chromiumos_image.bin" @@ -324,7 +319,11 @@ CHROMEOS_FACTORY_TEST_IMAGE_NAME="chromiumos_factory_image.bin" CHROMEOS_FACTORY_INSTALL_SHIM_NAME="factory_install_shim.bin" # Directory locations inside the dev chroot -CHROOT_TRUNK_DIR="/home/$USER/trunk" +if [ "${USER}" = "root" ]; then + CHROOT_TRUNK_DIR="/home/${SUDO_USER}/trunk" +else + CHROOT_TRUNK_DIR="/home/${USER}/trunk" +fi # Install make for portage ebuilds. Used by build_image and gmergefs. # TODO: Is /usr/local/autotest-chrome still used by anyone? @@ -452,12 +451,18 @@ assert_outside_chroot() { } assert_not_root_user() { - if [ $(id -u) = 0 ]; then + if [ ${UID:-$(id -u)} = 0 ]; then echo "This script must be run as a non-root user." exit 1 fi } +assert_root_user() { + if [ ${UID:-$(id -u)} != 0 ] || [ "${SUDO_USER:-root}" = "root" ]; then + die_notrace "This script must be run using sudo from a non-root user." + fi +} + # 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. @@ -534,6 +539,37 @@ sudo_multi() { fi } +# Writes stdin to the given file name as the sudo user in overwrite mode. +# +# $@ - The output file names. +user_clobber() { + install -m644 -o ${SUDO_UID} -g ${SUDO_GID} /dev/stdin "$@" +} + +# Appends stdin to the given file name as the sudo user. +# +# $1 - The output file name. +user_append() { + cat >> "$1" + chown ${SUDO_UID}:${SUDO_GID} "$1" +} + +# Create the specified directory, along with parents, as the sudo user. +# +# $@ - The directories to create. +user_mkdir() { + install -o ${SUDO_UID} -g ${SUDO_GID} -d "$@" +} + +# Create the specified symlink as the sudo user. +# +# $1 - Link target +# $2 - Link name +user_symlink() { + ln -sfT "$1" "$2" + chown -h ${SUDO_UID}:${SUDO_GID} "$2" +} + # Locate all mounts below a specified directory. # # $1 - The root tree. @@ -585,15 +621,11 @@ safe_umount_tree() { } -# Helper; all scripts should use this since it ensures our -# override of umount is used (inside the chroot, it's enforced -# via configuration; outside is the concern). -# Args are passed directly to umount; no sudo args are allowed. +# Run umount as root. safe_umount() { - sudo "${SCRIPT_ROOT}/path-overrides/umount" "$@" + $([ ${UID:-$(id -u)} != 0 ] && echo sudo) umount "$@" } - get_git_id() { git var GIT_COMMITTER_IDENT | sed -e 's/^.*<\(\S\+\)>.*$/\1/' } @@ -1080,23 +1112,6 @@ switch_to_strict_mode() { # TODO: Re-enable this once shflags is set -e safe. #switch_to_strict_mode -# The following code is used to ensure our umount wrapper is in use. -# Shouldn't be invoked by anything other than common.sh -_enable_path_overrides(){ - # Ensure that our PATH overrides are in use. - local override_dir=$(readlink -f "${SCRIPT_ROOT}/path-overrides") - local IFS=: - local x - for x in ${PATH}; do - x=$(readlink -f "${x}") - if [ "${x}" = "${override_dir}" ]; then - # Already is in path; nothing more to do. - return - fi - done - export PATH="${override_dir}${PATH:+:${PATH}}" -} - okboat() { # http://www.chris.com/ascii/index.php?art=transportation/nautical echo -e "${V_BOLD_GREEN}" @@ -1127,5 +1142,3 @@ BOAT echo -e "${V_VIDOFF}" die "$* failed" } - -_enable_path_overrides diff --git a/sdk_lib/enter_chroot.sh b/sdk_lib/enter_chroot.sh index 76b387adf8..8e44686854 100755 --- a/sdk_lib/enter_chroot.sh +++ b/sdk_lib/enter_chroot.sh @@ -9,11 +9,9 @@ SCRIPT_ROOT=$(readlink -f $(dirname "$0")/..) . "${SCRIPT_ROOT}/common.sh" || exit 1 -enable_strict_sudo - -# Script must be run outside the chroot and as a regular user. +# Script must be run outside the chroot and as root. assert_outside_chroot -assert_not_root_user +assert_root_user # Define command line flags # See http://code.google.com/p/shflags/wiki/Documentation10x @@ -25,14 +23,12 @@ DEFINE_string build_number "" \ "The build-bot build number (when called by buildbot only)." "b" DEFINE_string chrome_root "" \ "The root of your chrome browser source. Should contain a 'src' subdir." -DEFINE_string chrome_root_mount "/home/$USER/chrome_root" \ +DEFINE_string chrome_root_mount "/home/${SUDO_USER}/chrome_root" \ "The mount point of the chrome broswer source in the chroot." DEFINE_string cache_dir "" "Directory to use for caching." DEFINE_boolean official_build $FLAGS_FALSE \ "Set CHROMEOS_OFFICIAL=1 for release builds." -DEFINE_boolean mount $FLAGS_FALSE "Only set up mounts." -DEFINE_boolean unmount $FLAGS_FALSE "Only tear down mounts." DEFINE_boolean ssh_agent $FLAGS_TRUE "Import ssh agent." DEFINE_boolean early_make_chroot $FLAGS_FALSE \ "Internal flag. If set, the command is run as root without sudo." @@ -47,7 +43,7 @@ the chroot environment. For example: $0 FOO=bar BAZ=bel If [-- command] is present, runs the command inside the chroot, -after changing directory to /$USER/trunk/src/scripts. Note that neither +after changing directory to /${SUDO_USER}/trunk/src/scripts. Note that neither the command nor args should include single quotes. For example: $0 -- ./build_platform_packages.sh @@ -56,6 +52,7 @@ Otherwise, provides an interactive shell. " CROS_LOG_PREFIX=cros_sdk:enter_chroot +SUDO_HOME=$(eval echo ~${SUDO_USER}) # Version of info from common.sh that only echos if --verbose is set. debug() { @@ -89,30 +86,21 @@ FILES_TO_COPY_TO_CHROOT=( INNER_CHROME_ROOT=$FLAGS_chrome_root_mount # inside chroot CHROME_ROOT_CONFIG="/var/cache/chrome_root" # inside chroot -INNER_DEPOT_TOOLS_ROOT="/home/$USER/depot_tools" # inside chroot +INNER_DEPOT_TOOLS_ROOT="/home/${SUDO_USER}/depot_tools" # inside chroot FUSE_DEVICE="/dev/fuse" -AUTOMOUNT_PREF="/apps/nautilus/preferences/media_automount" -SAVED_AUTOMOUNT_PREF_FILE="/tmp/.automount_pref" -# Avoid the sudo call if possible since it is a little slow. -if [ $(stat -c %a "$FLAGS_chroot/var/lock") != 777 ]; then - sudo chmod 0777 "$FLAGS_chroot/var/lock" -fi +chmod 0777 "$FLAGS_chroot/var/lock" LOCKFILE="$FLAGS_chroot/var/lock/enter_chroot" -SYNCERPIDFILE="${FLAGS_chroot}/var/tmp/enter_chroot_sync.pid" - - MOUNTED_PATH=$(readlink -f "$FLAGS_chroot") -mount_queue_init() { - MOUNT_QUEUE=() -} -queue_mount() { +setup_mount() { # If necessary, mount $source in the host FS at $target inside the - # chroot directory with $mount_args. + # chroot directory with $mount_args. We don't write to /etc/mtab because + # these mounts are all contained within an unshare and are therefore + # inaccessible to other namespaces (e.g. the host desktop system). local source="$1" - local mount_args="$2" + local mount_args="-n $2" local target="$3" local mounted_path="${MOUNTED_PATH}$target" @@ -122,59 +110,17 @@ queue_mount() { # Already mounted! ;; *) - MOUNT_QUEUE+=( "mkdir -p '${mounted_path}'" ) + mkdir -p "${mounted_path}" # The args are left unquoted on purpose. if [[ -n ${source} ]]; then - MOUNT_QUEUE+=( "mount ${mount_args} '${source}' '${mounted_path}'" ) + mount ${mount_args} "${source}" "${mounted_path}" else - MOUNT_QUEUE+=( "mount ${mount_args} '${mounted_path}'" ) + mount ${mount_args} "${mounted_path}" fi ;; esac } -process_mounts() { - if [[ ${#MOUNT_QUEUE[@]} -eq 0 ]]; then - return 0 - fi - sudo_multi "${MOUNT_QUEUE[@]}" - mount_queue_init -} - -env_sync_proc() { - # This function runs and performs periodic updates to the chroot env, if - # necessary. - - local poll_interval=10 - local sync_files=( etc/resolv.conf etc/hosts ) - - # Make sure the files exist before the find -- they might not in a - # fresh chroot which results in warnings in the build output. - local chown_cmd=( - # Make sure the files exists first -- they might not in a fresh chroot. - "touch ${sync_files[*]/#/${FLAGS_chroot}/}" - # Make sure the files are writable by normal user so that we don't have - # to execute sudo in the main loop below. - "chown ${USER} ${sync_files[*]/#/${FLAGS_chroot}/}" - ) - sudo_multi "${chown_cmd[@]}" - - # Drop stdin, stderr, stdout, and chroot lock. - # This is needed for properly daemonizing the process. - exec 0>&- 1>&- 2>&- 200>&- - - while true; do - # Sync files - for file in "${sync_files[@]}"; do - if ! cmp /${file} ${FLAGS_chroot}/${file} &> /dev/null; then - cp -f /${file} ${FLAGS_chroot}/${file} - fi - done - - sleep ${poll_interval} - done -} - copy_ssh_config() { # Copy user .ssh/config into the chroot filtering out strings not supported # by the chroot ssh. The chroot .ssh directory is passed in as the first @@ -188,7 +134,7 @@ copy_ssh_config() { 'GSSAPIKeyExchange' 'ProxyUseFdpass' ) - local sshc="${HOME}/.ssh/config" + local sshc="${SUDO_HOME}/.ssh/config" local chroot_ssh_dir="${1}" local filter local option @@ -206,13 +152,13 @@ copy_ssh_config() { fi done - sed "/^.*\(${filter}\).*$/d" "${sshc}" > "${chroot_ssh_dir}/config" + sed "/^.*\(${filter}\).*$/d" "${sshc}" | \ + user_clobber "${chroot_ssh_dir}/config" } copy_into_chroot_if_exists() { # $1 is file path outside of chroot to copy to path $2 inside chroot. - [ -e "$1" ] || return - cp "$1" "${FLAGS_chroot}/$2" + [ -e "$1" ] && cp -p "$1" "${FLAGS_chroot}/$2" } # Usage: promote_api_keys @@ -222,22 +168,22 @@ copy_into_chroot_if_exists() { # have been used since the concept of keys got added, as well as before # and after the developer decding to grab his own keys. promote_api_keys() { - local destination="${FLAGS_chroot}/home/${USER}/.googleapikeys" + local destination="${FLAGS_chroot}/home/${SUDO_USER}/.googleapikeys" # Don't disturb existing keys. They could be set differently if [[ -s "${destination}" ]]; then return 0 fi - if [[ -r "${HOME}/.googleapikeys" ]]; then - cp "${HOME}/.googleapikeys" "${destination}" + if [[ -r "${SUDO_HOME}/.googleapikeys" ]]; then + cp -p "${SUDO_HOME}/.googleapikeys" "${destination}" if [[ -s "${destination}" ]] ; then info "Copied Google API keys into chroot." fi - elif [[ -r "${HOME}/.gyp/include.gypi" ]]; then + elif [[ -r "${SUDO_HOME}/.gyp/include.gypi" ]]; then local NAME="('google_(api_key|default_client_(id|secret))')" local WS="[[:space:]]*" local CONTENTS="('[^\\\\']*')" sed -nr -e "/^${WS}${NAME}${WS}[:=]${WS}${CONTENTS}.*/{s//\1: \4,/;p;}" \ - "${HOME}/.gyp/include.gypi" >"${destination}" + "${SUDO_HOME}/.gyp/include.gypi" | user_clobber "${destination}" if [[ -s "${destination}" ]]; then info "Put discovered Google API keys into chroot." fi @@ -245,73 +191,29 @@ promote_api_keys() { } setup_env() { - # Validate sudo timestamp before entering the critical section so that we - # don't stall for a password while we have the lockfile. - # Don't use sudo -v since that has issues on machines w/ no password. - sudo echo "" > /dev/null - ( flock 200 - echo $$ >> "$LOCKFILE" - # If there isn't a syncer daemon started already, start one. The - # daemon is considered to not be started under the following - # conditions: - # - # o There is no PID file - # - # o The PID file is 0 bytes in size, which might be a partial - # manifestation of chromium-os:17680. This situation will not - # occur anymore, but you might have a chroot which was already - # affected. - # - # o The /proc node for the process named by the PID file does - # not exist. - # - # Note: This does not address PID recycling. While - # increasingly unlikely, it is possible for the PID in - # the PID file to refer to a running process that is not - # the syncer process. Since the PID file is now - # removed, I think it is only possible for this to occur - # if your system crashes and the PID file exists after - # restart. - # - # The daemon is killed by the enter_chroot that exits last. - if [ -f "${SYNCERPIDFILE}" ] && [ ! -s "${SYNCERPIDFILE}" ] ; then - info "You may have suffered from chromium-os:17680 and"; - info "could have stray 'enter_chroot.sh' processes running."; - info "You must manually kill any such stray processes."; - info "Exit all chroot shells; remaining 'enter_chroot.sh'"; - info "processes are probably stray."; - sudo rm -f "${SYNCERPIDFILE}"; - fi; - if ! [ -f "${SYNCERPIDFILE}" ] || \ - ! [ -d /proc/$(<"${SYNCERPIDFILE}") ]; then - debug "Starting sync process" - env_sync_proc & - echo $! > "${SYNCERPIDFILE}" - disown $! - fi + # Make the lockfile writable for backwards compatibility. + chown ${SUDO_UID}:${SUDO_GID} "${LOCKFILE}" + + # Refresh /etc/resolv.conf and /etc/hosts in the chroot. + install -C -m644 /etc/resolv.conf ${FLAGS_chroot}/etc/resolv.conf + install -C -m644 /etc/hosts ${FLAGS_chroot}/etc/hosts debug "Mounting chroot environment." MOUNT_CACHE=$(echo $(awk '{print $2}' /proc/mounts)) - mount_queue_init - queue_mount none "-t proc" /proc - queue_mount none "-t sysfs" /sys - queue_mount /dev "--bind" /dev - queue_mount none "-t devpts" /dev/pts + setup_mount none "-t proc" /proc + setup_mount none "-t sysfs" /sys + setup_mount /dev "--bind" /dev + setup_mount none "-t devpts" /dev/pts if [ -d /run ]; then - queue_mount /run "--bind" /run + setup_mount /run "--bind" /run if [ -d /run/shm ]; then - queue_mount /run/shm "--bind" /run/shm + setup_mount /run/shm "--bind" /run/shm fi fi - # Get path overrides for the chroot in place now- it's possible - # that they may be needed for early teardown. - queue_mount "${FLAGS_trunk}/src/scripts/path-overrides" "--bind" \ - "/usr/local/path-overrides" - - queue_mount "${FLAGS_trunk}" "--bind" "${CHROOT_TRUNK_DIR}" + setup_mount "${FLAGS_trunk}" "--bind" "${CHROOT_TRUNK_DIR}" debug "Setting up referenced repositories if required." REFERENCE_DIR=$(git config --file \ @@ -322,17 +224,17 @@ setup_env() { ALTERNATES="${FLAGS_trunk}/.repo/alternates" # Ensure this directory exists ourselves, and has the correct ownership. - [ -d "${ALTERNATES}" ] || mkdir "${ALTERNATES}" - [ -w "${ALTERNATES}" ] || sudo chown -R "${USER}" "${ALTERNATES}" + user_mkdir "${ALTERNATES}" unset ALTERNATES IFS=$'\n'; - required=( $( "${FLAGS_trunk}/chromite/lib/rewrite_git_alternates.py" \ + required=( $( sudo -u "${SUDO_USER}" -- \ + "${FLAGS_trunk}/chromite/lib/rewrite_git_alternates.py" \ "${FLAGS_trunk}" "${REFERENCE_DIR}" "${CHROOT_TRUNK_DIR}" ) ) unset IFS - queue_mount "${FLAGS_trunk}/.repo/chroot/alternates" --bind \ + setup_mount "${FLAGS_trunk}/.repo/chroot/alternates" --bind \ "${CHROOT_TRUNK_DIR}/.repo/alternates" # Note that as we're bringing up each referened repo, we also @@ -343,13 +245,13 @@ setup_env() { # # Finally note that if you're unfamiliar w/ chroot/vfs semantics, # the bind is visible only w/in the chroot. - mkdir -p ${FLAGS_trunk}/.repo/chroot/empty + user_mkdir ${FLAGS_trunk}/.repo/chroot/empty position=1 for x in "${required[@]}"; do base="${CHROOT_TRUNK_DIR}/.repo/chroot/external${position}" - queue_mount "${x}" "--bind" "${base}" + setup_mount "${x}" "--bind" "${base}" if [ -e "${x}/.repo/alternates" ]; then - queue_mount "${FLAGS_trunk}/.repo/chroot/empty" "--bind" \ + setup_mount "${FLAGS_trunk}/.repo/chroot/empty" "--bind" \ "${base}/.repo/alternates" fi position=$(( ${position} + 1 )) @@ -360,9 +262,9 @@ setup_env() { chroot_cache='/var/cache/chromeos-cache' debug "Setting up shared cache dir directory." - mkdir -p "${FLAGS_cache_dir}"/distfiles/{target,host} - sudo mkdir -p "${FLAGS_chroot}/${chroot_cache}" - queue_mount "${FLAGS_cache_dir}" "--bind" "${chroot_cache}" + user_mkdir "${FLAGS_cache_dir}"/distfiles/{target,host} + user_mkdir "${FLAGS_chroot}/${chroot_cache}" + setup_mount "${FLAGS_cache_dir}" "--bind" "${chroot_cache}" # TODO(build): remove this as of 12/01/12. # Because of how distfiles -> cache_dir was deployed, if this isn't # a symlink, we *know* the ondisk pathways aren't compatible- thus @@ -372,55 +274,51 @@ setup_env() { # While we're at it, ensure the var is exported w/in the chroot; it # won't exist if distfiles isn't a symlink. p="${FLAGS_chroot}/etc/profile.d/chromeos-cachedir.sh" - sudo_multi "rm -rf '${distfiles_path}'" \ - "ln -s chromeos-cache/distfiles '${distfiles_path}'" \ - "mkdir -p -m 775 '${p%/*}'" \ - "echo 'export CHROMEOS_CACHEDIR=${chroot_cache}' > '${p}'" \ - "chmod 0644 '${p}'" + rm -rf "${distfiles_path}" + ln -s chromeos-cache/distfiles "${distfiles_path}" + mkdir -p -m 775 "${p%/*}" + echo 'export CHROMEOS_CACHEDIR=${chroot_cache}' > "${p}" + chmod 0644 "${p}" fi if [ $FLAGS_ssh_agent -eq $FLAGS_TRUE ]; then - if [ -n "${SSH_AUTH_SOCK}" -a -d "${HOME}/.ssh" ]; then - TARGET_DIR="${FLAGS_chroot}/home/${USER}/.ssh" - mkdir -p "${TARGET_DIR}" + if [ -n "${SSH_AUTH_SOCK}" -a -d "${SUDO_HOME}/.ssh" ]; then + TARGET_DIR="${FLAGS_chroot}/home/${SUDO_USER}/.ssh" + user_mkdir "${TARGET_DIR}" # Ignore errors as some people won't have these files to copy. - cp "${HOME}"/.ssh/{known_hosts,*.pub} "${TARGET_DIR}/" 2>/dev/null || : + cp -p "${SUDO_HOME}"/.ssh/{known_hosts,*.pub} "${TARGET_DIR}/" \ + 2>/dev/null || : copy_ssh_config "${TARGET_DIR}" + chown -R ${SUDO_UID}:${SUDO_GID} "${TARGET_DIR}" # Don't try to bind mount the ssh agent dir if it has gone stale. ASOCK=${SSH_AUTH_SOCK%/*} if [ -d "${ASOCK}" ]; then - queue_mount "${ASOCK}" "--bind" "${ASOCK}" + setup_mount "${ASOCK}" "--bind" "${ASOCK}" fi fi fi - if [ -d "$HOME/.subversion" ]; then - TARGET="/home/${USER}/.subversion" - mkdir -p "${FLAGS_chroot}${TARGET}" - queue_mount "${HOME}/.subversion" "--bind" "${TARGET}" + if [ -d "$SUDO_HOME/.subversion" ]; then + TARGET="/home/${SUDO_USER}/.subversion" + user_mkdir "${FLAGS_chroot}${TARGET}" + setup_mount "${SUDO_HOME}/.subversion" "--bind" "${TARGET}" # Symbolic-link the .subversion directory so sandboxed subversion.class # clients can use it. - local cmds=() for d in \ - "${FLAGS_cache_dir}"/distfiles/{host,target}/svn-src/"${USER}"; do + "${FLAGS_cache_dir}"/distfiles/{host,target}/svn-src/"${SUDO_USER}"; do if [[ ! -L "${d}/.subversion" ]]; then - cmds+=( - "mkdir -p '${d}'" - "ln -sf /home/${USER}/.subversion '${d}/.subversion'" - "chown -R ${USER}:250 '${d%/*}'" - ) + rm -rf "${d}/.subversion" + user_mkdir "${d}" + user_symlink /home/${SUDO_USER}/.subversion "${d}/.subversion" fi done - if [[ ${#cmds[@]} -gt 0 ]]; then - sudo_multi "${cmds[@]}" - fi fi - if DEPOT_TOOLS=$(type -P gclient) ; then - DEPOT_TOOLS=${DEPOT_TOOLS%/*} # dirname + # A reference to the DEPOT_TOOLS path may be passed in by cros_sdk. + if [ -n "${DEPOT_TOOLS}" ]; then debug "Mounting depot_tools" - queue_mount "$DEPOT_TOOLS" --bind "$INNER_DEPOT_TOOLS_ROOT" + setup_mount "${DEPOT_TOOLS}" --bind "${INNER_DEPOT_TOOLS_ROOT}" fi # Mount additional directories as specified in .local_mounts file. @@ -438,14 +336,12 @@ setup_env() { # if only source is assigned, use source as mount point. : ${mount_point:=${mount_source}} debug " mounting ${mount_source} on ${mount_point}" - queue_mount "${mount_source}" "--bind" "${mount_point}" + setup_mount "${mount_source}" "--bind" "${mount_point}" # --bind can't initially be read-only so we have to do it via remount. - queue_mount "" "-o remount,ro" "${mount_point}" + setup_mount "" "-o remount,ro" "${mount_point}" done < <(sed -e 's:#.*::' "${local_mounts}") fi - process_mounts - CHROME_ROOT="$(readlink -f "$FLAGS_chrome_root" || :)" if [ -z "$CHROME_ROOT" ]; then CHROME_ROOT="$(cat "${FLAGS_chroot}${CHROME_ROOT_CONFIG}" \ @@ -455,68 +351,38 @@ setup_env() { if [[ -n "$CHROME_ROOT" ]]; then if [[ ! -d "${CHROME_ROOT}/src" ]]; then error "Not mounting chrome source" - sudo rm -f "${FLAGS_chroot}${CHROME_ROOT_CONFIG}" + rm -f "${FLAGS_chroot}${CHROME_ROOT_CONFIG}" if [[ ! "$CHROME_ROOT_AUTO" ]]; then exit 1 fi else debug "Mounting chrome source at: $INNER_CHROME_ROOT" - sudo bash -c "echo '$CHROME_ROOT' > \ - '${FLAGS_chroot}${CHROME_ROOT_CONFIG}'" - queue_mount "$CHROME_ROOT" --bind "$INNER_CHROME_ROOT" + echo $CHROME_ROOT > "${FLAGS_chroot}${CHROME_ROOT_CONFIG}" + setup_mount "$CHROME_ROOT" --bind "$INNER_CHROME_ROOT" fi fi - process_mounts - # Install fuse module. Skip modprobe when possible for slight # speed increase when initializing the env. if [ -c "${FUSE_DEVICE}" ] && ! grep -q fuse /proc/filesystems; then - sudo modprobe fuse 2> /dev/null ||\ + modprobe fuse 2> /dev/null ||\ warn "-- Note: modprobe fuse failed. gmergefs will not work" fi - # Turn off automounting of external media when we enter the - # chroot; thus we don't have to worry about being able to unmount - # from inside. - if SAVED_PREF=$(gconftool-2 -g ${AUTOMOUNT_PREF} 2>/dev/null); then - if [ "${SAVED_PREF}" != "false" ]; then - if [ $(gconftool-2 -s --type=boolean ${AUTOMOUNT_PREF} false) ]; then - warn "-- Note: USB sticks may be automounted by your host OS." - warn "-- Note: If you plan to burn bootable media, you may need to" - warn "-- Note: unmount these devices manually, or run image_to_usb.sh" - warn "-- Note: outside the chroot." - fi - fi - fi - # Always write the temp file so we can read it when exiting - echo "${SAVED_PREF:-false}" > "${FLAGS_chroot}${SAVED_AUTOMOUNT_PREF_FILE}" - # Fix permissions on ccache tree. If this is a fresh chroot, then they # might not be set up yet. Or if the user manually `rm -rf`-ed things, # we need to reset it. Otherwise, gcc itself takes care of fixing things # on demand, but only when it updates. ccache_dir="${FLAGS_chroot}/var/cache/distfiles/ccache" if [[ ! -d ${ccache_dir} ]]; then - sudo mkdir -p -m 2775 "${ccache_dir}" + mkdir -p -m 2775 "${ccache_dir}" fi - sudo find -H "${ccache_dir}" -type d -exec chmod 2775 {} + & - sudo find -H "${ccache_dir}" -gid 0 -exec chgrp 250 {} + & - - # Configure committer username and email in chroot .gitconfig. Change - # to the root directory first so that random $PWD/.git/config settings - # do not get picked up. We want to stick to ~/.gitconfig only. - ident=$(cd /; git var GIT_COMMITTER_IDENT || :) - ident_name=${ident%% <*} - ident_email=${ident%%>*}; ident_email=${ident_email##*<} - git config -f ${FLAGS_chroot}/home/${USER}/.gitconfig --replace-all \ - user.name "${ident_name}" || true - git config -f ${FLAGS_chroot}/home/${USER}/.gitconfig --replace-all \ - user.email "${ident_email}" || true + find -H "${ccache_dir}" -type d -exec chmod 2775 {} + & + find -H "${ccache_dir}" -gid 0 -exec chgrp 250 {} + & # Certain files get copied into the chroot when entering. for fn in "${FILES_TO_COPY_TO_CHROOT[@]}"; do - copy_into_chroot_if_exists "${HOME}/${fn}" "/home/${USER}/${fn}" + copy_into_chroot_if_exists "${SUDO_HOME}/${fn}" "/home/${SUDO_USER}/${fn}" done promote_api_keys @@ -545,25 +411,23 @@ setup_env() { # with long multibyte strings. Newer setups have this fixed, # but locale-gen doesn't need to be run in any locale in the # first place, so just go with C to keep it fast. - sudo -- chroot "$FLAGS_chroot" env LC_ALL=C locale-gen -q -u \ + chroot "$FLAGS_chroot" env LC_ALL=C locale-gen -q -u \ -G "$(printf '%s\n' "${gen_locales[@]}")" fi # Fix permissions on shared memory to allow non-root users access to POSIX - # semaphores. Avoid the sudo call if possible (sudo is slow). - if [ -n "$(find "${FLAGS_chroot}/dev/shm" ! -perm 777)" ] ; then - sudo chmod -R 777 "${FLAGS_chroot}/dev/shm" - fi + # semaphores. + chmod -R 777 "${FLAGS_chroot}/dev/shm" # If the private overlays are installed, gsutil can use those credentials. # We're also installing credentials for use by sudoed invocations. boto='src/private-overlays/chromeos-overlay/googlestorage_account.boto' if [ -s "${FLAGS_trunk}/${boto}" ]; then - if [ ! -e "${FLAGS_chroot}/home/${USER}/.boto" ]; then - ln -s "trunk/${boto}" "${FLAGS_chroot}/home/${USER}/.boto" + if [ ! -e "${FLAGS_chroot}/home/${SUDO_USER}/.boto" ]; then + user_symlink "trunk/${boto}" "${FLAGS_chroot}/home/${SUDO_USER}/.boto" fi if [ ! -e "${FLAGS_chroot}/root/.boto" ]; then - sudo ln -s "../home/${USER}/trunk/${boto}" "${FLAGS_chroot}/root/.boto" + ln -s "../home/${SUDO_USER}/trunk/${boto}" "${FLAGS_chroot}/root/.boto" fi fi @@ -571,95 +435,13 @@ setup_env() { # as a result of old gsutil or tools. This causes permission errors when # gsutil cp tries to create its cache files, so ensure the user can # actually write to their directory. - gsutil_dir="${FLAGS_chroot}/home/${USER}/.gsutil" - if [ -d "${gsutil_dir}" ] && [ ! -w "${gsutil_dir}" ]; then - sudo chown -R "${USER}:$(id -gn)" "${gsutil_dir}" + gsutil_dir="${FLAGS_chroot}/home/${SUDO_USER}/.gsutil" + if [ -d "${gsutil_dir}" ]; then + chown -R ${SUDO_UID}:${SUDO_GID} "${gsutil_dir}" fi ) 200>>"$LOCKFILE" || die "setup_env failed" } -teardown_env() { - # Validate sudo timestamp before entering the critical section so that we - # don't stall for a password while we have the lockfile. - # Don't use sudo -v since that has issues on machines w/ no password. - sudo echo "" > /dev/null - - # Only teardown if we're the last enter_chroot to die - ( - flock 200 - - # check each pid in $LOCKFILE to see if it's died unexpectedly - TMP_LOCKFILE="$LOCKFILE.tmp" - - echo -n > "$TMP_LOCKFILE" # Erase/reset temp file - cat "$LOCKFILE" | while read PID; do - if [ "$PID" = "$$" ]; then - # ourself, leave PROC_NAME empty - PROC_NAME="" - else - PROC_NAME=$(ps --pid $PID -o comm=) - fi - - if [ ! -z "$PROC_NAME" ]; then - # All good, keep going - echo "$PID" >> "$TMP_LOCKFILE" - fi - done - # Remove any dups from lock file while installing new one - sort -u -n "$TMP_LOCKFILE" > "$LOCKFILE" - - SAVED_PREF=$(<"${FLAGS_chroot}${SAVED_AUTOMOUNT_PREF_FILE}") - if [ "${SAVED_PREF}" != "false" ]; then - gconftool-2 -s --type=boolean ${AUTOMOUNT_PREF} ${SAVED_PREF} || \ - warn "could not re-set your automount preference." - fi - - if [ -s "$LOCKFILE" ]; then - debug "At least one other pid is running in the chroot, so not" - debug "tearing down env." - else - debug "Stopping syncer process" - # If another process entering the chroot is blocked on this - # flock in setup_env(), it can be a race condition. - # - # When this locked region is exited, the setup_env() flock can - # be entered before the script can exit and the /proc entry for - # the PID is removed. The newly-created chroot will not end up - # with a syncer process. To avoid that situation, remove the - # syncer PID file. - # - # The syncer PID file should also be removed because the kernel - # will reuse PIDs. It's possible that the PID in the syncer PID - # has been reused by another process; make sure we don't skip - # starting the syncer process when this occurs by deleting the - # PID file. - kill $(<"${SYNCERPIDFILE}") && \ - { rm -f "${SYNCERPIDFILE}" 2>/dev/null || \ - sudo rm -f "${SYNCERPIDFILE}" ; } || - debug "Unable to clean up syncer process."; - - debug "Unmounting chroot environment." - safe_umount_tree "${MOUNTED_PATH}/" - fi - ) 200>>"$LOCKFILE" || die "teardown_env failed" -} - -if [ $FLAGS_mount -eq $FLAGS_TRUE ]; then - setup_env - info "Make sure you run" - info " $0 --unmount" - info "before deleting $FLAGS_chroot" - info "or you'll end up deleting $FLAGS_trunk too!" - exit 0 -fi - -if [ $FLAGS_unmount -eq $FLAGS_TRUE ]; then - teardown_env - exit 0 -fi - -# Make sure we unmount before exiting -trap teardown_env EXIT setup_env CHROOT_PASSTHRU=( @@ -668,15 +450,9 @@ CHROOT_PASSTHRU=( "EXTERNAL_TRUNK_PATH=${FLAGS_trunk}" ) -# Add the standard proxied variables, and a few we specifically -# export for script usage; USE/GCC_GITHASH are for ebuilds/portage, -# CHROMEOS_VERSION_* is for cros_set_lsb_release and local AU server -# (builders export this for marking reasons). -KEEP_VARS=( - CHROMEOS_VERSION_{TRACK,AUSERVER,DEVSERVER} - USE GCC_GITHASH -) -for var in "${ENVIRONMENT_WHITELIST[@]}" "${KEEP_VARS[@]}"; do +# Add the whitelisted environment variables to CHROOT_PASSTHRU. +load_environment_whitelist +for var in "${ENVIRONMENT_WHITELIST[@]}" ; do [ "${!var+set}" = "set" ] && CHROOT_PASSTHRU+=( "${var}=${!var}" ) done @@ -692,11 +468,8 @@ elif [ ! -x "${FLAGS_chroot}/usr/bin/sudo" ]; then error "Requested enter_chroot command was: $@" exit 127 else - cmd=( sudo -i -u "$USER" ) + cmd=( sudo -i -u "${SUDO_USER}" ) fi -sudo -- chroot "${FLAGS_chroot}" "${cmd[@]}" "${CHROOT_PASSTHRU[@]}" "$@" - -# Remove trap and explicitly unmount -trap - EXIT -teardown_env +cmd+=( "${CHROOT_PASSTHRU[@]}" "$@" ) +exec chroot "${FLAGS_chroot}" "${cmd[@]}" diff --git a/sdk_lib/make_chroot.sh b/sdk_lib/make_chroot.sh index e48757be67..6915f26584 100755 --- a/sdk_lib/make_chroot.sh +++ b/sdk_lib/make_chroot.sh @@ -14,8 +14,6 @@ SCRIPT_ROOT=$(readlink -f $(dirname "$0")/..) ENTER_CHROOT=$(readlink -f $(dirname "$0")/enter_chroot.sh) -enable_strict_sudo - if [ -n "${USE}" ]; then echo "$SCRIPT_NAME: Building with a non-empty USE: ${USE}" echo "This modifies the expected behaviour and can fail." @@ -28,8 +26,9 @@ if [[ "$ARCHITECTURE" != "x86_64" ]]; then exit 1 fi -# Script must be run outside the chroot. +# Script must be run outside the chroot and as root. assert_outside_chroot +assert_root_user # Define command line flags. # See http://code.google.com/p/shflags/wiki/Documentation10x @@ -54,8 +53,8 @@ eval set -- "${FLAGS_ARGV}" check_flags_only_and_allow_null_arg "$@" && set -- CROS_LOG_PREFIX=cros_sdk:make_chroot +SUDO_HOME=$(eval echo ~${SUDO_USER}) -assert_not_root_user # Set the right umask for chroot creation. umask 022 @@ -86,13 +85,13 @@ fi # Support faster build if necessary. EMERGE_CMD="emerge" if [ "$FLAGS_fast" -eq "${FLAGS_TRUE}" ]; then - CHROOT_CHROMITE_DIR="/home/${USER}/trunk/chromite" + CHROOT_CHROMITE_DIR="/home/${SUDO_USER}/trunk/chromite" EMERGE_CMD="${CHROOT_CHROMITE_DIR}/bin/parallel_emerge" fi ENTER_CHROOT_ARGS=( CROS_WORKON_SRCROOT="$CHROOT_TRUNK" - PORTAGE_USERNAME="$USER" + PORTAGE_USERNAME="${SUDO_USER}" IGNORE_PREFLIGHT_BINHOST="$IGNORE_PREFLIGHT_BINHOST" ) @@ -114,8 +113,8 @@ early_enter_chroot() { # Run a command within the chroot. The main usage of this is to avoid # the overhead of enter_chroot, and do not need access to the source tree, # don't need the actual chroot profile env, and can run the command as root. -sudo_chroot() { - sudo chroot "${FLAGS_chroot}" "$@" +bare_chroot() { + chroot "${FLAGS_chroot}" "$@" } cleanup() { @@ -131,120 +130,115 @@ delete_existing() { info "Cleaning up old mount points..." cleanup info "Deleting $FLAGS_chroot..." - sudo rm -rf "$FLAGS_chroot" + rm -rf "$FLAGS_chroot" info "Done." } init_users () { info "Set timezone..." # date +%Z has trouble with daylight time, so use host's info. - sudo rm -f "${FLAGS_chroot}/etc/localtime" + rm -f "${FLAGS_chroot}/etc/localtime" if [ -f /etc/localtime ] ; then - sudo cp /etc/localtime "${FLAGS_chroot}/etc" + cp /etc/localtime "${FLAGS_chroot}/etc" else - sudo ln -sf /usr/share/zoneinfo/PST8PDT "${FLAGS_chroot}/etc/localtime" + ln -sf /usr/share/zoneinfo/PST8PDT "${FLAGS_chroot}/etc/localtime" fi info "Adding user/group..." # Add ourselves as a user inside the chroot. - sudo_chroot groupadd -g 5000 eng + bare_chroot groupadd -g 5000 eng # We need the UID to match the host user's. This can conflict with # a particular chroot UID. At the same time, the added user has to # be a primary user for the given UID for sudo to work, which is # determined by the order in /etc/passwd. Let's put ourselves on top # of the file. - sudo_chroot useradd -o -G ${DEFGROUPS} -g eng -u `id -u` -s \ - /bin/bash -m -c "${FULLNAME}" -p ${CRYPTED_PASSWD} ${USER} + bare_chroot useradd -o -G ${DEFGROUPS} -g eng -u ${SUDO_UID} -s \ + /bin/bash -m -c "${FULLNAME}" -p ${CRYPTED_PASSWD} ${SUDO_USER} # Because passwd generally isn't sorted and the entry ended up at the # bottom, it is safe to just take it and move it to top instead. - sudo sed -e '1{h;d};$!{H;d};$G' -i "${FLAGS_chroot}/etc/passwd" + sed -e '1{h;d};$!{H;d};$G' -i "${FLAGS_chroot}/etc/passwd" } init_setup () { info "Running init_setup()..." - sudo mkdir -p -m 755 "${FLAGS_chroot}/usr" \ + mkdir -p -m 755 "${FLAGS_chroot}/usr" \ "${FLAGS_chroot}/usr/local/portage" \ "${FLAGS_chroot}"/"${CROSSDEV_OVERLAY}" - sudo ln -sf "${CHROOT_TRUNK}/src/third_party/portage" \ + ln -sf "${CHROOT_TRUNK}/src/third_party/portage" \ "${FLAGS_chroot}/usr/portage" - sudo ln -sf "${CHROOT_TRUNK}/src/third_party/chromiumos-overlay" \ + ln -sf "${CHROOT_TRUNK}/src/third_party/chromiumos-overlay" \ "${FLAGS_chroot}"/"${CHROOT_OVERLAY}" - sudo ln -sf "${CHROOT_TRUNK}/src/third_party/portage-stable" \ + ln -sf "${CHROOT_TRUNK}/src/third_party/portage-stable" \ "${FLAGS_chroot}"/"${PORTAGE_STABLE_OVERLAY}" # Some operations need an mtab. - sudo ln -s /proc/mounts "${FLAGS_chroot}/etc/mtab" + ln -s /proc/mounts "${FLAGS_chroot}/etc/mtab" # Set up sudoers. Inside the chroot, the user can sudo without a password. # (Safe enough, since the only way into the chroot is to 'sudo chroot', so # the user's already typed in one sudo password...) # Make sure the sudoers.d subdir exists as older stage3 base images lack it. - sudo mkdir -p "${FLAGS_chroot}/etc/sudoers.d" + mkdir -p "${FLAGS_chroot}/etc/sudoers.d" # Use the standardized upgrade script to setup proxied vars. - sudo bash -e "${SCRIPT_ROOT}/chroot_version_hooks.d/45_rewrite_sudoers.d" \ - "${FLAGS_chroot}" "${USER}" "${ENVIRONMENT_WHITELIST[@]}" + load_environment_whitelist + bash -e "${SCRIPT_ROOT}/chroot_version_hooks.d/45_rewrite_sudoers.d" \ + "${FLAGS_chroot}" "${SUDO_USER}" "${ENVIRONMENT_WHITELIST[@]}" - # Turn on the path overrides; subshelled to protect our env from whatever - # vars the scriptlet may bleed. - ( CROS_CHROOT="${FLAGS_chroot}" - . "${SCRIPT_ROOT}/chroot_version_hooks.d/47_path_overrides" ) - - sudo find "${FLAGS_chroot}/etc/"sudoers* -type f -exec chmod 0440 {} + + find "${FLAGS_chroot}/etc/"sudoers* -type f -exec chmod 0440 {} + # Fix bad group for some. - sudo chown -R root:root "${FLAGS_chroot}/etc/"sudoers* + chown -R root:root "${FLAGS_chroot}/etc/"sudoers* info "Setting up hosts/resolv..." # Copy config from outside chroot into chroot. - sudo cp /etc/{hosts,resolv.conf} "$FLAGS_chroot/etc/" - sudo chmod 0644 "$FLAGS_chroot"/etc/{hosts,resolv.conf} + cp /etc/{hosts,resolv.conf} "$FLAGS_chroot/etc/" + chmod 0644 "$FLAGS_chroot"/etc/{hosts,resolv.conf} # Setup host make.conf. This includes any overlay that we may be using # and a pointer to pre-built packages. # TODO: This should really be part of a profile in the portage. info "Setting up /etc/make.*..." - sudo mv "${FLAGS_chroot}"/etc/make.conf{,.orig} - sudo ln -sf "${CHROOT_CONFIG}/make.conf.amd64-host" \ + mv "${FLAGS_chroot}"/etc/make.conf{,.orig} + ln -sf "${CHROOT_CONFIG}/make.conf.amd64-host" \ "${FLAGS_chroot}/etc/make.conf" - sudo mv "${FLAGS_chroot}"/etc/make.profile{,.orig} - sudo ln -sf "${CHROOT_OVERLAY}/profiles/default/linux/amd64/10.0" \ + mv "${FLAGS_chroot}"/etc/make.profile{,.orig} + ln -sf "${CHROOT_OVERLAY}/profiles/default/linux/amd64/10.0" \ "${FLAGS_chroot}/etc/make.profile" # Create make.conf.user . - sudo touch "${FLAGS_chroot}"/etc/make.conf.user - sudo chmod 0644 "${FLAGS_chroot}"/etc/make.conf.user + touch "${FLAGS_chroot}"/etc/make.conf.user + chmod 0644 "${FLAGS_chroot}"/etc/make.conf.user # Create directories referred to by our conf files. - sudo mkdir -p -m 775 "${FLAGS_chroot}/var/lib/portage/pkgs" \ + mkdir -p -m 775 "${FLAGS_chroot}/var/lib/portage/pkgs" \ "${FLAGS_chroot}/var/cache/"chromeos-{cache,chrome} \ "${FLAGS_chroot}/etc/profile.d" - echo "export CHROMEOS_CACHEDIR=/var/cache/chromeos-cache" | \ - sudo_clobber "${FLAGS_chroot}/etc/profile.d/chromeos-cachedir.sh" - sudo_multi \ - "chmod 0644 '${FLAGS_chroot}/etc/profile.d/chromeos-cachedir.sh'" \ - "rm -rf '${FLAGS_chroot}/var/cache/distfiles'" \ - "ln -s chromeos-cache/distfiles '${FLAGS_chroot}/var/cache/distfiles'" + echo "export CHROMEOS_CACHEDIR=/var/cache/chromeos-cache" > \ + "${FLAGS_chroot}/etc/profile.d/chromeos-cachedir.sh" + chmod 0644 "${FLAGS_chroot}/etc/profile.d/chromeos-cachedir.sh" + rm -rf "${FLAGS_chroot}/var/cache/distfiles" + ln -s chromeos-cache/distfiles "${FLAGS_chroot}/var/cache/distfiles" # Run this from w/in the chroot so we use whatever uid/gid # these are defined as w/in the chroot. - sudo_chroot chown "${USER}:portage" /var/cache/chromeos-chrome + bare_chroot chown "${SUDO_USER}:portage" /var/cache/chromeos-chrome # These are created for compatibility while transitioning # make.conf and friends over to the new location. # TODO(ferringb): remove this 01/13 or so. - sudo ln -s ../../cache/chromeos-cache/distfiles/host \ + ln -s ../../cache/chromeos-cache/distfiles/host \ "${FLAGS_chroot}/var/lib/portage/distfiles" - sudo ln -s ../../cache/chromeos-cache/distfiles/target \ + ln -s ../../cache/chromeos-cache/distfiles/target \ "${FLAGS_chroot}/var/lib/portage/distfiles-target" # Add chromite/bin and depot_tools into the path globally; note that the # chromite wrapper itself might also be found in depot_tools. # We rely on 'env-update' getting called below. target="${FLAGS_chroot}/etc/env.d/99chromiumos" - sudo_clobber "${target}" < "${target}" +PATH=/home/${SUDO_USER}/trunk/chromite/bin:/home/${SUDO_USER}/depot_tools CROS_WORKON_SRCROOT="${CHROOT_TRUNK}" -PORTAGE_USERNAME=$USER +PORTAGE_USERNAME=${SUDO_USER} EOF # TODO(zbehan): Configure stuff that is usually configured in postinst's, @@ -260,8 +254,8 @@ EOF /usr/local/portage/chromiumos/profiles/default/linux/amd64/10.0 target="${FLAGS_chroot}/etc/profile.d" - sudo mkdir -p "${target}" - sudo_clobber "${target}/chromiumos-niceties.sh" << EOF + mkdir -p "${target}" + cat << EOF > "${target}/chromiumos-niceties.sh" # Niceties for interactive logins. (cr) denotes this is a chroot, the # __git_branch_ps1 prints current git branch in ./ . The $r behavior is to # make sure we don't reset the previous $? value which later formats in @@ -278,40 +272,53 @@ EOF # http://crosbug.com/20378 local localegen="$FLAGS_chroot/etc/locale.gen" if ! grep -q -v -e '^#' -e '^$' "${localegen}" ; then - sudo_append "${localegen}" <> "${localegen}" en_US ISO-8859-1 en_US.UTF-8 UTF-8 EOF fi # Add chromite as a local site-package. - mkdir -p "${FLAGS_chroot}/home/$USER/.local/lib/python2.6/site-packages" - ln -s ../../../../trunk/chromite \ - "${FLAGS_chroot}/home/$USER/.local/lib/python2.6/site-packages/" + local site_packages="/home/${SUDO_USER}/.local/lib/python2.6/site-packages" + user_mkdir "${FLAGS_chroot}${site_packages}" + user_symlink ../../../../trunk/chromite \ + "${FLAGS_chroot}${site_packages}/chromite" - chmod a+x "$FLAGS_chroot/home/$USER/.bashrc" # Automatically change to scripts directory. echo 'cd ${CHROOT_CWD:-~/trunk/src/scripts}' \ - >> "$FLAGS_chroot/home/$USER/.bash_profile" + | user_append "$FLAGS_chroot/home/${SUDO_USER}/.bash_profile" # Enable bash completion for build scripts. echo ". ~/trunk/src/scripts/bash_completion" \ - >> "$FLAGS_chroot/home/$USER/.bashrc" + | user_append "$FLAGS_chroot/home/${SUDO_USER}/.bashrc" - if [[ "$USER" = "chrome-bot" ]]; then + if [[ "${SUDO_USER}" = "chrome-bot" ]]; then # Copy ssh keys, so chroot'd chrome-bot can scp files from chrome-web. - cp -r ~/.ssh "$FLAGS_chroot/home/$USER/" + cp -rp ~/.ssh "$FLAGS_chroot/home/${SUDO_USER}/" fi - if [[ -f $HOME/.gitconfig ]]; then + if [[ -f ${SUDO_HOME}/.gitconfig ]]; then # Copy .gitconfig into chroot so repo and git can be used from inside. # This is required for repo to work since it validates the email address. echo "Copying ~/.gitconfig into chroot" - cp $HOME/.gitconfig "$FLAGS_chroot/home/$USER/" + cp -p "${SUDO_HOME}/.gitconfig" "$FLAGS_chroot/home/${SUDO_USER}/" fi - if [[ -f $HOME/.cros_chroot_init ]]; then - /bin/bash $HOME/.cros_chroot_init "${FLAGS_chroot}" + # If the user didn't set up their username in their gitconfig, look + # at the default git settings for the user. + if ! git config -f "${SUDO_HOME}/.gitconfig" user.email >& /dev/null; then + ident=$(cd /; sudo -u ${SUDO_USER} -- git var GIT_COMMITTER_IDENT || :) + ident_name=${ident%% <*} + ident_email=${ident%%>*}; ident_email=${ident_email##*<} + gitconfig=${FLAGS_chroot}/home/${SUDO_USER}/.gitconfig + git config -f ${gitconfig} --replace-all user.name "${ident_name}" || : + git config -f ${gitconfig} --replace-all user.email "${ident_email}" || : + chown ${SUDO_UID}:${SUDO_GID} ${FLAGS_chroot}/home/${SUDO_USER}/.gitconfig + fi + + if [[ -f ${SUDO_HOME}/.cros_chroot_init ]]; then + sudo -u ${SUDO_USER} -- /bin/bash "${SUDO_HOME}/.cros_chroot_init" \ + "${FLAGS_chroot}" fi } @@ -343,7 +350,7 @@ done # Create the base Gentoo stage3 based on last version put in chroot. STAGE3="${OVERLAY}/chromeos/stage3/stage3-amd64-${FLAGS_stage3_date}.tar.bz2" if [ -f $CHROOT_STATE ] && \ - ! sudo egrep -q "^STAGE3=$STAGE3" $CHROOT_STATE >/dev/null 2>&1 + ! egrep -q "^STAGE3=$STAGE3" $CHROOT_STATE >/dev/null 2>&1 then info "STAGE3 version has changed." delete_existing @@ -372,8 +379,8 @@ else *) die "Unknown tarball compression: ${STAGE3}";; esac ${DECOMPRESS} -dc "${STAGE3}" | \ - sudo tar -xp -C "${FLAGS_chroot}" - sudo rm -f "$FLAGS_chroot/etc/"make.{globals,conf.user} + tar -xp -C "${FLAGS_chroot}" + rm -f "$FLAGS_chroot/etc/"make.{globals,conf.user} fi # Set up users, if needed, before mkdir/mounts below. @@ -382,7 +389,7 @@ fi echo info "Setting up mounts..." # Set up necessary mounts and make sure we clean them up on exit. -sudo mkdir -p "${FLAGS_chroot}/${CHROOT_TRUNK}" "${FLAGS_chroot}/run" +mkdir -p "${FLAGS_chroot}/${CHROOT_TRUNK}" "${FLAGS_chroot}/run" # Create a special /etc/make.conf.host_setup that we use to bootstrap # the chroot. The regular content for the file will be generated the @@ -411,7 +418,7 @@ fi # Add file to indicate that it is a chroot. # Add version of $STAGE3 for update checks. -sudo sh -c "echo STAGE3=$STAGE3 > $CHROOT_STATE" +echo STAGE3=$STAGE3 > $CHROOT_STATE info "Updating portage" early_enter_chroot emerge -uNv --quiet portage