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