view sources/utility_functions.sh @ 1513:06c06aeaf547

Brown-paper-bag bug: sanitize_environment assembles a whitelist in an environment variable, and didn't include that variable in the whitelist. (So if the variable name was already used, it wouldn't be at the end of the list, and would blank itself, and everything after it...)
author Rob Landley <rob@landley.net>
date Sat, 24 Mar 2012 18:16:29 -0500
parents 9a3f7ada5cb1
children b8dbb8d7d6cc
line wrap: on
line source

#!/bin/echo "This file is sourced, not run"

# This file contains generic functions, presumably reusable in other contexts.

# Unset all environment variables that we don't know about, in case some crazy
# person already exported $CROSS_COMPILE, $ARCH, $CDPATH, or who knows what
# else.  It's hard to know what might drive some package crazy, so use a
# whitelist.

sanitize_environment()
{
  # Which variables are set in config?

  TEMP=$(echo $(sed -n 's/.*export[ \t]*\([^=]*\)=.*/\1/p' config) | sed 's/ /,/g')

  # What other variables should we keep?

  TEMP="$TEMP,LANG,PATH,SHELL,TERM,USER,USERNAME,LOGNAME,PWD,EDITOR,HOME,DISPLAY,_"
  TEMP="$TEMP,TOPSHELL,START_TIME,STAGE_NAME,TOOLCHAIN_PREFIX,HOST_ARCH,WRAPPY_LOGPATH,OLDPATH"
  TEMP="$TEMP,http_proxy,ftp_proxy,https_proxy,no_proxy,TEMP"

  # Unset any variable we don't recognize.  It can screw up the build.

  for i in $(env | sed -n 's/=.*//p')
  do
    is_in_list $i "$TEMP" && continue
    [ "${i:0:7}" == "DISTCC_" ] && continue
    [ "${i:0:7}" == "CCACHE_" ] && continue

    unset $i 2>/dev/null
  done
}

# Assign (export) a variable only if current value is blank

export_if_blank()
{
  [ -z "$(eval "echo \"\${${1/=*/}}\"")" ] && export "$1"
}

# Create a blank directory at first argument, deleting existing contents if any

blank_tempdir()
{
  # sanity test: never rm -rf something we don't own.
  [ -z "$1" ] && dienow
  touch -c "$1" || dienow

  # Delete old directory, create new one.
  [ -z "$NO_CLEANUP" ] && rm -rf "$1"
  mkdir -p "$1" || dienow
}

# output the sha1sum of a file

sha1file()
{
  sha1sum "$@" | awk '{print $1}'
}

# dienow() is an exit function that works properly even from a subshell.
# (actually_dienow is run in the parent shell via signal handler.)

actually_dienow()
{
  echo -e "\n\e[31mExiting due to errors ($ARCH_NAME $STAGE_NAME $PACKAGE)\e[0m" >&2
  exit 1
}

trap actually_dienow SIGUSR1
TOPSHELL=$$

dienow()
{
  kill -USR1 $TOPSHELL
  exit 1
}

# Turn a bunch of output lines into a much quieter series of periods,
# roughly one per screenfull

dotprogress()
{
  x=0
  while read i
  do
    x=$[$x + 1]
    if [[ "$x" -eq 25 ]]
    then
      x=0
      echo -n .
    fi
  done
  echo
}

# Announce an action to the world

announce()
{
  # Write a line to the log file with easily greppable header
  echo "=== $1 ($ARCH_NAME $STAGE_NAME)"

  # Set the title bar of the current xterm
  [ -z "$NO_TITLE_BAR" ] && echo -en "\033]2;$ARCH_NAME $STAGE_NAME $1\007"
}

# Filter out unnecessary noise, keeping just lines starting with "==="

maybe_quiet()
{
  [ -z "$FORK" ] && cat || grep "^==="
}

# Run a command background if FORK is set, in foreground otherwise

maybe_fork()
{
  [ -z "$BUILD_VERBOSE" ] || echo "$*"

  if [ -z "$FORK" ]
  then
    eval "$*"
  else
    eval "$*" &
  fi
}

# Kill a process and all its decendants

killtree()
{
  local KIDS=""

  while [ $# -ne 0 ]
  do
    KIDS="$KIDS $(pgrep -P$1)"
    shift
  done

  KIDS="$(echo -n $KIDS)"
  if [ ! -z "$KIDS" ]
  then
    # Depth first kill avoids reparent_to_init hiding stuff.
    killtree $KIDS
    kill $KIDS 2>/dev/null
  fi
}

# Search a colon-separated path for files matching a pattern.

# Arguments are 1) path to search, 2) pattern, 3) command to run on each file.
# During command, $DIR/$FILE points to file found.

path_search()
{
  # For each each $PATH element, loop through each file in that directory,
  # and create a symlink to the wrapper with that name.  In the case of
  # duplicates, keep the first one.

  echo "$1" | sed 's/:/\n/g' | while read DIR
  do
    find "$DIR/" -maxdepth 1 -mindepth 1 -name "$2" | sed 's@.*/@@' | \
    while read FILE
    do
      eval "$3"

      # Output is verbose.  Pipe it to dotprogress.

      echo $FILE
    done
  done
}

# Abort if we haven't got a prerequisite in the $PATH

check_prerequisite()
{
  if [ -z "$(which "$1")" ]
  then
    [ -z "$FAIL_QUIET" ] && echo No "$1" in '$PATH'. >&2
    dienow
  fi
}

# Search through all the files under a directory and collapse together
# identical files into hardlinks

collapse_hardlinks()
{
  SHA1LIST=""
  find "$1" -type f | while read FILE
  do
    echo "$FILE"
    SHA1=$(sha1file "$FILE")
    MATCH=$(echo "$SHA1LIST" | grep "^$SHA1")
    if [ -z "$MATCH" ]
    then
      # Yes, the quote spanning two lines here is intentional
      SHA1LIST="$SHA1LIST
$SHA1 $FILE"
    else
      FILE2="$(echo "$MATCH" | sed 's/[^ ]* //')"
      cmp -s "$FILE" "$FILE2" || continue
      ln -f "$FILE" "$FILE2" || dienow
    fi
  done
}

# Check if $1 is in the comma separated list $2

is_in_list()
{
  [ "$2" == all ] || [ ! -z "$(echo ,"$2", | grep ,"$1",)" ]
}