7b79ae
#!/bin/bash
7b79ae
7b79ae
# If using normal root, avoid changing anything.
7b79ae
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
7b79ae
  exit 0
7b79ae
fi
7b79ae
7b79ae
exclude_files=""
7b79ae
exclude_files_from=""
7b79ae
exclude_shebangs=""
7b79ae
exclude_shebangs_from=""
7b79ae
7b79ae
usage() {
7b79ae
  local verbose=$1 && shift
7b79ae
  local outfile=$1 && shift
7b79ae
  local status=$1 && shift
7b79ae
7b79ae
  (
7b79ae
    echo 'usage: brp-mangle-shebangs [--files <regexp>] [--files-from <file>] [--shebangs <regexp>] [--shebangs-from <file>]'
7b79ae
    if [ "${verbose}" == "yes" ]; then
7b79ae
      echo '  --files: extended regexp of files to ignore'
7b79ae
      echo '  --files-from: file containing a list of extended regexps of files to ignore'
7b79ae
      echo '  --shebangs: extended regexp of shebangs to ignore'
7b79ae
      echo '  --shebangs-from: file containing a list of extended regexps of shebangs to ignore'
7b79ae
    fi
7b79ae
  ) >>${outfile}
7b79ae
  exit ${status}
7b79ae
}
7b79ae
7b79ae
while [ $# -gt 0 ] ; do
7b79ae
  case "$1" in
7b79ae
    --files)
7b79ae
      exclude_files="${2}"
7b79ae
      shift
7b79ae
      ;;
7b79ae
    --files=*)
7b79ae
      exclude_files="${1##--files=}"
7b79ae
      ;;
7b79ae
    --files-from)
7b79ae
      exclude_files_from="${2}"
7b79ae
      shift
7b79ae
      ;;
7b79ae
    --files-from=*)
7b79ae
      exclude_files_from="${1##--files-from=}"
7b79ae
      ;;
7b79ae
    --shebangs)
7b79ae
      exclude_shebangs="${2}"
7b79ae
      shift
7b79ae
      ;;
7b79ae
    --shebangs=*)
7b79ae
      exclude_shebangs="${1##--shebangs=}"
7b79ae
      ;;
7b79ae
    --shebangs-from)
7b79ae
      exclude_shebangs_from="${2}"
7b79ae
      shift
7b79ae
      ;;
7b79ae
    --shebangs-from=*)
7b79ae
      exclude_shebangs_from="${1##--shebangs-from=}"
7b79ae
      ;;
7b79ae
    --help|--usage|"-?"|-h)
7b79ae
      usage yes /dev/stdout 0
7b79ae
      ;;
7b79ae
    *)
7b79ae
      echo "Unknown option \"${1}\"" 1>&2
7b79ae
      usage no /dev/stderr 1
7b79ae
      ;;
7b79ae
  esac
7b79ae
  shift
7b79ae
done
7b79ae
7b79ae
cd "$RPM_BUILD_ROOT"
7b79ae
db9905
# Large packages such as kernel can have thousands of executable files.
db9905
# We take care to not fork/exec thousands of "file"s and "grep"s,
db9905
# but run just two of them.
db9905
# (Take care to exclude filenames which would mangle "file" output).
db9905
find -executable -type f ! -path '*:*' ! -path $'*\n*' \
db9905
| file -N --mime-type -f - \
db9905
| grep -P ".+(?=: text/)" \
db9905
| {
7b79ae
fail=0
db9905
while IFS= read -r line; do
db9905
  f=${line%%:*}
7b79ae
7b79ae
  # Remove the dot
7b79ae
  path="${f#.}"
7b79ae
7b79ae
  if [ -n "$exclude_files" ]; then
7b79ae
    echo "$path" | grep -q -E "$exclude_files" && continue
7b79ae
  fi
7b79ae
  if [ -n "$exclude_files_from" ]; then
7b79ae
    echo "$path" | grep -q -E -f "$exclude_files_from" && continue
7b79ae
  fi
7b79ae
7b79ae
34881d
  if ! read shebang_line < "$f"; then
34881d
    echo >&2 "*** WARNING: Cannot read the first line from $f, removing executable bit"
34881d
    ts=$(stat -c %y "$f")
34881d
    chmod -x "$f"
34881d
    touch -d "$ts" "$f"
34881d
    continue
34881d
  fi
34881d
db9905
  orig_shebang="${shebang_line#\#!}"
db9905
  if [ "$orig_shebang" = "$shebang_line" ]; then
db9905
    echo >&2 "*** WARNING: $f is executable but has no shebang, removing executable bit"
db9905
    ts=$(stat -c %y "$f")
db9905
    chmod -x "$f"
db9905
    touch -d "$ts" "$f"
db9905
    continue
7b79ae
  fi
7b79ae
db9905
  # Trim spaces
db9905
  while shebang="${orig_shebang//  / }"; [ "$shebang" != "$orig_shebang" ]; do
db9905
    orig_shebang="$shebang"
db9905
  done
db9905
  # Treat "#! /path/to " as "#!/path/to"
db9905
  orig_shebang="${orig_shebang# }"
db9905
db9905
  shebang="$orig_shebang"
db9905
7b79ae
  if [ -z "$shebang" ]; then
db9905
    echo >&2 "*** WARNING: $f is executable but has empty shebang, removing executable bit"
db9905
    ts=$(stat -c %y "$f")
7b79ae
    chmod -x "$f"
7b79ae
    touch -d "$ts" "$f"
7b79ae
    continue
db9905
  fi
db9905
  if [ -n "${shebang##/*}" ]; then
7b79ae
    echo >&2 "*** ERROR: $f has shebang which doesn't start with '/' ($shebang)"
7b79ae
    fail=1
7b79ae
    continue
7b79ae
  fi
7b79ae
7b79ae
  if ! { echo "$shebang" | grep -q -P "^/(?:usr/)?(?:bin|sbin)/"; }; then
7b79ae
    continue
7b79ae
  fi
7b79ae
7b79ae
  # Replace "special" env shebang:
7b79ae
  # /whatsoever/env /whatever/foo → /whatever/foo
7b79ae
  shebang=$(echo "$shebang" | sed -r -e 's@^(.+)/env /(.+)$@/\2@')
7b79ae
  # /whatsoever/env foo → /whatsoever/foo
7b79ae
  shebang=$(echo "$shebang" | sed -r -e 's@^(.+/)env (.+)$@\1\2@')
7b79ae
7b79ae
  # Replace python3 with the desired Python 3 shebang,
7b79ae
  # if passed as an non-empty environment variable PYTHON3
7b79ae
  if [ -n "${PYTHON3:+x}" ]; then
7b79ae
    shebang=$(echo "$shebang" | sed -r -e "s@/usr/bin/python3(\s|$)@${PYTHON3}\1@")
7b79ae
  fi
7b79ae
7b79ae
  # Replace ambiguous python with python2
7b79ae
  py_shebang=$(echo "$shebang" | sed -r -e 's@/usr/bin/python(\s|$)@/usr/bin/python2\1@')
7b79ae
7b79ae
  if [ "$shebang" != "$py_shebang" ]; then
7b79ae
    echo >&2 "*** ERROR: ambiguous python shebang in $path: #!$orig_shebang. Change it to python3 (or python2) explicitly."
7b79ae
    fail=1
7b79ae
  elif [ "#!$shebang" != "#!$orig_shebang" ]; then
7b79ae
    echo "mangling shebang in $path from $orig_shebang to #!$shebang"
db9905
    ts=$(stat -c %y "$f")
db9905
    sed -i -e "1c #!$shebang" "$f"
db9905
    touch -d "$ts" "$f"
7b79ae
  fi
7b79ae
db9905
done
7b79ae
7b79ae
exit $fail
db9905
}