#!/bin/bash
#
# This script must be run in the location of the script!
#
# This script generates Android.bp files for this and all subdirs of this
#
DIR="${ANDROID_BUILD_TOP}/external/crosvm/jail/seccomp"

function remove_trailing_slash {
  if [[ $1 == "/" ]]; then
    echo $i
  else
    echo ${1%/}
  fi
}

set -o errexit

function check_location() {
  local my_loc="$(realpath ${DIR})"
  my_loc=$(remove_trailing_slash ${my_loc})

  local my_pwd="$(realpath $PWD)"
  my_pwd="$(remove_trailing_slash ${my_pwd})"
  if [[ "${my_loc}" != "${my_pwd}" ]]; then
    echo ${my_loc}
    echo ${my_pwd}
    >&2 echo "the script location must be run where the script is located"
    exit 10
  fi
}

my_name=`basename $0`
all_archs=("x86_64" "aarch64" "arm" "x86" "riscv64")
seccomp_archs=("x86_64" "aarch64")

# define arch dir pattern: e.g. ${ARCH}-linux-gnu
function get_arch_dir() {
  local suffix="-linux-gnu"
  local arch=$1
  echo ${arch}${suffix}
}

# convert seccomp arch to bp arch
function get_bp_arch() {
  [ $1 = "aarch64" ] && echo "arm64" || echo $1
}

# utility function to enumerate policy files
#
# 1: seccomp dir to scan
function scan_policy_name() {
  local seccomp_dir=$1
  (
    # pushd but no output to stdout/stderr
    # the output is taken and used by the caller
    pushd $seccomp_dir > /dev/null 2>&1
    ls \
      `# Not policy files.` \
       --hide=constants.json \
      `# Non-root policy files.` \
       --hide=common_device.policy \
       --hide=common_device.frequency \
       --hide=gpu_common.policy \
       --hide=serial.policy \
       --hide=net.policy \
       --hide=block.policy \
       --hide=vhost_user.policy \
       --hide=vhost_vsock.policy \
      `# Root policy files we don't need yet.` \
       --hide=net_device_vhost_user.policy \
       --hide=swap_monitor.policy \
       --hide=vhost_vsock_device_vhost_user.policy \
       -1
    popd > /dev/null 2>&1
  )
}

function gen_license() {
  local cchars=${1:-"//"}
  local year=${2:-"2020"}
cat <<EOF
${cchars} Autogenerated via ${my_name}
${cchars}
${cchars} Copyright (C) ${year} The Android Open Source Project
${cchars}
${cchars} Licensed under the Apache License, Version 2.0 (the "License");
${cchars} you may not use this file except in compliance with the License.
${cchars} You may obtain a copy of the License at
${cchars}
${cchars}      http://www.apache.org/licenses/LICENSE-2.0
${cchars}
${cchars} Unless required by applicable law or agreed to in writing, software
${cchars} distributed under the License is distributed on an "AS IS" BASIS,
${cchars} WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
${cchars} See the License for the specific language governing permissions and
${cchars} limitations under the License.

${cchars} DO NOT MODIFY DIRECTLY, ALL CHANGES WILL BE OVERWRITTEN BY ${my_name}

EOF
}

function gen_blueprint_boilerplate() {
cat <<EOF
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "external_crosvm_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    //   SPDX-license-identifier-BSD
    default_applicable_licenses: ["external_crosvm_license"],
}

python_binary_host {
    name: "detect_duplication",
    main: "detect_duplication.py",
    srcs: [
        "detect_duplication.py",
    ],
}

genrule_defaults {
    name: "crosvm_inline_seccomp_policy_x86_64",
    cmd: "set -o pipefail; \$(location policy-inliner.sh) \$(location x86_64/common_device.policy) \$(location x86_64/gpu_common.policy) \$(location x86_64/serial.policy) \$(location x86_64/net.policy) \$(location x86_64/block.policy) \$(location x86_64/vhost_user.policy) \$(location x86_64/vhost_vsock.policy) < \$(in) | \$(location detect_duplication) > \$(out)",
    tools: [
        "detect_duplication",
    ],
    tool_files: [
        "policy-inliner.sh",
        "x86_64/common_device.policy",
        "x86_64/gpu_common.policy",
        "x86_64/serial.policy",
        "x86_64/net.policy",
        "x86_64/block.policy",
        "x86_64/vhost_user.policy",
        "x86_64/vhost_vsock.policy",
    ],
}

genrule_defaults {
    name: "crosvm_inline_seccomp_policy_aarch64",
    cmd: "set -o pipefail; \$(location policy-inliner.sh) \$(location aarch64/common_device.policy) \$(location aarch64/gpu_common.policy) \$(location aarch64/serial.policy) \$(location aarch64/net.policy) DOESNT_EXIST DOESNT_EXIST DOESNT_EXIST DOESNT_EXIST < \$(in) | \$(location detect_duplication) > \$(out)",
    tools: [
        "detect_duplication",
    ],
    tool_files: [
        "policy-inliner.sh",
        "aarch64/common_device.policy",
        "aarch64/gpu_common.policy",
        "aarch64/serial.policy",
        "aarch64/net.policy",
    ],
}

EOF
}

function gen_blueprint_arch_policy_files() {
  local archs=("$@")
  declare -A policy_genrules
  for arch in ${archs[@]}; do
    for file in $(scan_policy_name ${arch}); do
      local base_name="$(basename $file)"
      policy_genrules[${base_name}]="${policy_genrules[${base_name}]} $arch"
    done
  done
  for file in "${!policy_genrules[@]}"; do
    for arch in ${policy_genrules[$file]}; do
      echo "genrule {"
      echo "    name: \"${file}_inline_${arch}\","
      echo "    defaults: [\"crosvm_inline_seccomp_policy_${arch}\"],"
      echo "    out: [\"${file}\"],"
      echo "    srcs: [\"${arch}/${file}\"],"
      echo "}"
      echo
      if [[ $arch != "arm" ]]; then
        echo "prebuilt_usr_share_host {"
        echo "    name: \"${file}_${arch}\","
        echo "    filename: \"${file}\","
        echo "    relative_install_path: \"crosvm/$(get_arch_dir ${arch})/seccomp\","
        echo "    src: \":${file}_inline_${arch}\","
        echo "}"
        echo
      fi
    done
    echo "prebuilt_etc {"
    echo "    name: \"${file}\","
    echo "    relative_install_path: \"seccomp_policy/crosvm\","
    declare -a target_archs
    echo "    arch: {"
    declare -a disabled_archs=${all_archs[@]}
    for arch in ${policy_genrules[$file]}; do
      disabled_archs=("${disabled_archs[@]/$arch}")
      local bp_arch=$(get_bp_arch ${arch})
      echo "        ${bp_arch}: {"
      echo "            src: \":${file}_inline_${arch}\","
      echo "        },"
    done
    echo "    },"
    echo "    target: {"
    for arch in ${disabled_archs[@]}; do
      local bp_arch=$(get_bp_arch ${arch})
      echo "        android_${bp_arch}: {"
      echo "            enabled: false,"
      echo "        },"
    done
    echo "    },"
    echo "}"
    echo
  done
}

function gen_crosvm_seccomp_policy_product_packages_mk_fragment() {
  local archs=("$@")
  declare -A policy_genrules
  for arch in ${archs[@]}; do
    for file in $(scan_policy_name ${arch}); do
      local base_name="$(basename $file)"
      policy_genrules[${base_name}]="${policy_genrules[${base_name}]} $arch"
    done
  done
  echo "PRODUCT_PACKAGES += \\"
  for file in "${!policy_genrules[@]}"; do
    echo "    ${file} \\"
  done | sort
  echo

  echo "# TODO: Remove this when crosvm is added to generic system image"
  echo "PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \\"
  for file in "${!policy_genrules[@]}"; do
    echo "    system/etc/seccomp_policy/crosvm/${file} \\"
  done | sort
}

function print_host_seccomp_policy_lists() {
  local archs=("$@")
  echo "Please update the following blocks in device/google/cuttlefish/build/Android.bp:"
  for arch in ${archs[@]}; do
    echo
    echo "cvd_host_seccomp_policy_${arch} = ["
    for file in $(scan_policy_name ${arch}); do
      local base_name="$(basename $file)"
      echo "    \"${file}_${arch}\","
    done | sort
    echo "]"
  done
}

# main
check_location
gen_license >Android.bp
gen_license \# >crosvm_seccomp_policy_product_packages.mk
gen_blueprint_boilerplate >>Android.bp
gen_blueprint_arch_policy_files "${seccomp_archs[@]}" >>Android.bp
gen_crosvm_seccomp_policy_product_packages_mk_fragment \
  "${seccomp_archs[@]}" >>crosvm_seccomp_policy_product_packages.mk
print_host_seccomp_policy_lists "${seccomp_archs[@]}"
