Files
iopsyswrt/iop
2024-09-24 11:01:42 +02:00

523 lines
14 KiB
Bash
Executable File

#!/bin/bash
arg=$1
arr_index=0
declare -a command_array
declare -a help_array
# Check if we should clone feeds with ssh or http
developer=0
which git >/dev/null && git remote -v 2>/dev/null | grep -qE '(git@|ssh://)' && developer=1
# Utility functions
function register_command {
command_array[$arr_index]=$1
help_array[$arr_index]=$2
arr_index=$((arr_index+1))
}
function dump_commands {
for i in $(seq 0 $arr_index); do
output+=("${command_array[$i]}" "${help_array[$i]}")
done
printf "Available commands:\n"
printf " %-25s%s\n" "${output[@]}" | sort
printf "\n"
}
# Parse yaml file, look for specified feed definition and create feeds.conf-like output
function parse_yaml_feed() {
local yaml_file="$1"
local feed="$2"
local yaml_content=$(cat "$yaml_file")
# Extract the values
local names=($(echo "$yaml_content" | grep -oP '(?<=name: ).*'))
local urls=($(echo "$yaml_content" | grep -oP '(?<=uri: ).*'))
local revisions=($(echo "$yaml_content" | grep -oP '(?<=revision: ).*'))
# Create the output string
local output=""
for ((i=0; i<${#names[@]}; i++)); do
if [ ${names[i]} == ${feed} ]; then
output+="src-git-full ${names[i]} ${urls[i]}^${revisions[i]}\n"
fi
done
echo -e "$output"
}
function has_profiles_feed() {
# regex taken from ./scripts/feeds
grep -qP '^src-([\w\-]+)((?:\s+--\w+(?:=\S+)?)*)\s+(profiles)' feeds.conf
}
# Register bootstrap command that installs other commands from feeds
function bootstrap() {
cp feeds.conf.io feeds.conf
parse_yaml_feed "profiles/include/iop_feed.yml" iopsys >> feeds.conf
feeds=(iopsys)
if has_profiles_feed; then
feeds+=(profiles)
fi
if [ "$developer" == 1 ]; then
./scripts/feeds update -g "${feeds[@]}" || exit 1
else
./scripts/feeds update "${feeds[@]}" || exit 1
fi
./scripts/feeds install -p iopsys iop || exit 1
}
register_command "bootstrap" "Initial command to run to install other commands"
function install_locales()
{
sudo locale-gen en_US.UTF-8
}
function install_pkgs()
{
local packages_misc="
bc
bison
build-essential
ccache
cpio
curl
device-tree-compiler
dialog
execstack
file
flex
g++
g++-multilib
gawk
gdisk
gettext
git
automake
gtk-doc-tools
jq
libelf-dev
liblzo2-dev
libncurses5
libncurses5-dev
libssl-dev
ncurses-term
pv
python2
python-is-python2
python3
python3-cryptography
python3-distutils
python3-jsonschema
rsync
subversion
svn-buildpackage
swig
unzip
uuid-dev
wget
zlib1g-dev
xxd
cmake
quilt
cryptsetup
libcap-dev
libseccomp-dev
libyajl-dev
"
local packages_perl="libconvert-binary-c-perl libdigest-crc-perl"
# do we need 32 bit compatibility libs ?
if [ "$(uname -m | awk '{print$1}')" == "x86_64" ]; then
local packages_x64="libc6-dev-i386 lib32z1 libncurses5:i386"
fi
# filter out already installed packages
local packages_all="$packages_misc $packages_perl $packages_x64"
local needed=""
for pkg in $packages_all
do
if ! dpkg -s $pkg >/dev/null 2>/dev/null
then
needed="$needed $pkg"
fi
done
# install needed packages
if [ -n "$needed" ]
then
echo "Need to install dpkg packages [$needed]"
read -p "Do you approve installation of these packages (y/n): " ans
if [ "$ans" == "y" ]; then
sudo apt-get update && sudo apt-get install $needed || exit $?
else
echo "can't continue. aborting!"
exit 1
fi
fi
}
check_bash()
{
local mysh=$(ls -hl /bin/sh | awk -F'[ ,/]' '{print$NF}')
if [ "$mysh" != "bash" ]; then
echo "On Debian based systems, e.g. Ubuntu, /bin/sh must point to bash instead of $mysh"
read -p "Do you approve this change (y/n): " ans
if [ "$ans" == "y" ]; then
sudo rm -f /bin/sh
sudo ln -s bash /bin/sh
else
echo "Warning! You haven't pointed /bin/sh to bash."
exit 1
fi
fi
}
download_check_hash() {
local url="$1"
local sha256="$2"
local tarball="$(mktemp iop_brcm_tar.XXXXXXX)"
wget -nv "$url" -O "$tarball" || return 1
if ! sha256sum --quiet -c <(echo "${sha256} *${tarball}") >&2; then
echo "Hash mismatch of tarball $url (expected: $sha256)" >&2
sha256sum "$tarball" >&2
rm -f $tarball
return 1
fi
printf "%s" "$tarball"
}
download_extract_bcm() {
local type="$1"
local url="$2"
local sha256="$3"
local path="$4"
local path_strip_no=0
if [ ! -z "$5" ]; then
path_strip_no="$5"
fi
local tarball="$(download_check_hash "$url" "$sha256")"
if [ -z "$tarball" ]; then
echo "Error: Error occurred during download or hash verification for $url"
exit 1
fi
case "$type" in
toolchain)
# current 10.3/4.19/2.30/2.32 BCM toolchain has owner of files set to some employee who created the tar
# Change to root during extraction
sudo tar --owner=root --group=root -C "$path" --strip-components=$path_strip_no -Pxf "$tarball"
;;
hnd_toolchain)
sudo mkdir -p "$path" && \
sudo tar --owner=root --group=root -C "$path" -xf "$tarball" --strip-components=1
;;
wlan_fw_tools)
(
set -e
sudo mkdir -p "$path"
sudo unzip -j \
"$tarball" \
bcawlan-fw-build-post-process-tools/post-process-tools/\* \
-d "$path/bin"
sudo find "$path/bin" -type f -not -name '*.ini' -execdir chmod +x '{}' ';'
)
;;
*)
echo "Error: Unknown type $type" >&2
false
;;
esac
local ret=$?
rm -f "$tarball"
return "$ret"
}
check_brcm_tools(){
local install_arm=0
local install_arm_softfp=0
local install_arm_hf=0
local install_aarch64=0
local install_wlan_fw_tools=0
local TOOLCHAIN_DIR="/opt/toolchains/"
if [ ! -d ${TOOLCHAIN_DIR}/crosstools-arm-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1 ]; then
install_arm=1
echo "Need to install Broadcom ARM toolchain"
fi
if [ ! -d ${TOOLCHAIN_DIR}/crosstools-arm_softfp-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1 ]; then
install_arm_softfp=1
echo "Need to install Broadcom ARM-softfp toolchain"
fi
if [ ! -d ${TOOLCHAIN_DIR}crosstools-arm_hf-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1 ]; then
install_arm_hf=1
echo "Need to install Broadcom ARM-hf toolchain"
fi
if [ ! -d ${TOOLCHAIN_DIR}crosstools-aarch64-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1 ]; then
install_aarch64=1
echo "Need to install Broadcom aarch64 toolchain"
fi
if [ ! -d /opt/bcawlan-fw-build-post-process-tools ]; then
install_wlan_fw_tools=1
echo "Need to install bcawlan-fw-build-post-process-tools"
fi
if [ "$install_arm" -eq 1 \
-o "$install_arm_softfp" -eq 1 \
-o "$install_arm_hf" -eq 1 \
-o "$install_aarch64" -eq 1 \
-o "$install_wlan_fw_tools" -eq 1 ]; then
read -p "Do you approve installation of the aforementioned missing toolchains and tools (y/n): " ans
if [ "$ans" == "y" ]; then
echo "Downloading toolchain/tools"
else
echo "can't continue. aborting"
exit 1
fi
# create install dir
sudo mkdir -p ${TOOLCHAIN_DIR}
if [ $install_arm -eq 1 ]; then
echo "Installing ARM toolchain"
download_extract_bcm \
toolchain \
https://download.iopsys.eu/iopsys/toolchain/crosstools-arm-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1.Rel1.13.tar.bz2 \
38657d72a7726db3e13621784d3e1ad65e2721c0538e87cc38cf3266bde26d6f \
${TOOLCHAIN_DIR}
fi
if [ $install_arm_softfp -eq 1 ]; then
download_extract_bcm \
toolchain \
https://download.iopsys.eu/iopsys/toolchain/crosstools-arm_softfp-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1.Rel1.13.tar.bz2 \
9af29bac2ba6cbe51ee09467dbe97dc76a47bbf00df1fffafa1433817d2a147b \
${TOOLCHAIN_DIR}
fi
if [ $install_arm_hf -eq 1 ]; then
download_extract_bcm \
toolchain \
https://download.iopsys.eu/iopsys/toolchain/crosstools-arm_hf-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1.Rel1.13.tar.bz2 \
3e57bbbb5e0b832813aa93274dfa937260833af645c2bc03cb1c88d4e98def92 \
${TOOLCHAIN_DIR}
fi
if [ $install_aarch64 -eq 1 ]; then
echo "Installing aarch64 toolchain"
download_extract_bcm \
toolchain \
https://download.iopsys.eu/iopsys/toolchain/crosstools-aarch64-gcc-10.3-linux-4.19-glibc-2.32-binutils-2.36.1.Rel1.13.tar.bz2 \
aed8c327951a5a7bfd67f9d2e92f844923a216994764e0aa32903bd40ea8945a \
${TOOLCHAIN_DIR}
fi
if [ $install_wlan_fw_tools -eq 1 ]; then
echo "Installing bcawlan-fw-build-post-process-tools"
download_extract_bcm \
wlan_fw_tools \
https://download.iopsys.eu/iopsys/toolchain/bcawlan-fw-build-post-process-tools.zip \
1082d631317aef900ab2bfe549830bfbc76da87f21ff78cd3129f369f3f92101 \
/opt/bcawlan-fw-build-post-process-tools
fi
fi
}
check_gcc_version(){
gcc_ver=$(ls -l $(which gcc) | awk '{ print $NF }')
# if /usr/bin/gcc -> /etc/alternatives/cc
if [ -L $gcc_ver ]; then
gcc_ver=$(ls -l $gcc_ver | awk '{ print $NF }')
fi
# transform gcc-* to just a number.
gcc_ver=$(echo $gcc_ver | cut -d- -f2)
if [ "$gcc_ver" != 4.8 ]; then
echo "Your current gcc version is $gcc_ver, but it must be changed to 4.8"
read -p "Do you approve this change (y/n): " ans
if [ "$ans" == "y" ]; then
if ! dpkg -s gcc-4.8 >/dev/null 2>/dev/null ;then
sudo apt-get install gcc-4.8
fi
if ! dpkg -s g++-4.8 >/dev/null 2>/dev/null ;then
sudo apt-get install g++-4.8
fi
if ! dpkg -s gcc-4.8-multilib >/dev/null 2>/dev/null ;then
sudo apt-get install gcc-4.8-multilib
fi
sudo update-alternatives --install /usr/bin/g++ c++ /usr/bin/g++-4.8 100
sudo update-alternatives --install /usr/bin/g++ c++ /usr/bin/g++-$gcc_ver 90
sudo update-alternatives --install /usr/bin/gcc cc /usr/bin/gcc-4.8 100
sudo update-alternatives --install /usr/bin/gcc cc /usr/bin/gcc-$gcc_ver 90
sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-4.8 100
sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-$gcc_ver 90
sudo update-alternatives --set c++ /usr/bin/g++-4.8
sudo update-alternatives --set cc /usr/bin/gcc-4.8
sudo update-alternatives --set cpp /usr/bin/cpp-4.8
sudo ln -s /etc/alternatives/cc /usr/bin/cc
echo "The deafult gcc version has now been changed from $gcc_ver to 4.8"
fi
fi
}
restore_gcc() {
if dpkg -s gcc-5 >/dev/null 2>/dev/null
then
gcc_ver=$(ls -l $(which gcc) | awk '{ print $NF }')
# if /usr/bin/gcc -> /etc/alternatives/cc
if [ -L $gcc_ver ]; then
gcc_ver=$(ls -l $gcc_ver | awk '{ print $NF }')
fi
# transform gcc-* to just a number.
gcc_ver=$(echo $gcc_ver | cut -d- -f2)
# is 4.8 the default reset back to 5
if [ "$gcc_ver" = "4.8" ]; then
echo "Your current gcc version is $gcc_ver that is not the distro default. set it back to default ?"
read -p "Do you approve this change (y/n): " ans
if [ "$ans" == "y" ]; then
sudo update-alternatives --set c++ /usr/bin/g++-5
sudo update-alternatives --set cc /usr/bin/gcc-5
sudo update-alternatives --set cpp /usr/bin/cpp-5
# force a reinstall of default version
# yes it needs to be done twice.
sudo apt-get install --reinstall gcc cpp g++
sudo apt-get install --reinstall gcc cpp g++
fi
fi
fi
}
# Compare modification date of two files
# return 0 (true) if first file is older, 1 (false) otherwise
is_older() {
local target=$(stat -c %Y $1 2> /dev/null)
local ref=$(stat -c %Y $2 2> /dev/null)
[ -z "$target" -o -z "$ref" ] && return 1
[ $target -lt $ref ] && return 0
return 1
}
install_iop_completion() {
local instloc=/usr/share/bash-completion/completions/iop
local srcloc=./feeds/iopsys/iop/iop.completion
local inst=0
if [ ! -e $instloc ]; then
echo "Bash completion for './iop' utility not found"
inst=1
elif is_older $instloc $srcloc ; then
echo "Bash completion for './iop' utility is outdated"
inst=1
fi
if [ $inst -eq 1 ]; then
read -p "Install latest version to '$instloc' (y/n): " ans
if [ "$ans" == "y" ]; then
sudo cp $srcloc $instloc
echo "Start a new shell to enable ./iop command completion!"
fi
fi
}
function setup_host {
#===============#
# Prerequisites #
#===============#
install_locales
install_pkgs
check_bash
check_brcm_tools
#check_gcc_version
restore_gcc
install_iop_completion
echo ""
echo ""
echo "You have successfully installed and configred prerequisites to be able to build an iopsys firmware"
echo ""
echo ""
}
register_command "setup_host" "Install needed packets to host machine"
# Plugin scripts call register command to export their interface
if [ -d package/feeds/iopsys/iop/scripts ]; then
for f in package/feeds/iopsys/iop/scripts/*; do
source $f
done
fi
function feeds_update {
# Call bootstrap to update feeds/iopsys for transiton in old/new genconfig state
echo "Calling bootstrap to update required feeds"
bootstrap
# always return true
exit 0
}
register_command "feeds_update" "Compatibility function only"
function set-feed-rev() {
./scripts/set-feed-rev "$@"
}
register_command "set-feed-rev" "Update feeds revisions in feeds.conf.io and profiles"
# Register commands from external files
source ./scripts/genconfig_wrap.sh
source ./scripts/iopupgrade.sh
if [ -z $arg ] || [ $arg == "--help" ]; then
printf "Usage: iop <command> [<args>]\n\n"
dump_commands
exit -1
fi
# Check all registered commands for a match
for i in $(seq 0 $arr_index); do
if [ $arg == "${command_array[$i]}" ]; then
# Run the command and pass all args
# except for the first to it
$arg "${@:2}"
exit 0
fi
done
# No registered command for the passed input arg
printf "Error: no such command $arg\n\n"
dump_commands
exit -1