From 35a48627b66affb4f96cc200ba50cb3be321baea Mon Sep 17 00:00:00 2001 From: bryan Date: Thu, 11 Nov 2021 15:21:22 -0500 Subject: [PATCH] I heard you like rewrites --- .gitignore | 1 + .vscode/settings.json | 2 +- .vscode/tasks.json | 2 +- openwrtBuild | 488 -------------------------------- openwrtbuilder | 517 ++++++++++++++++++++++++++++++++++ openwrtbuilder.code-workspace | 13 + 6 files changed, 533 insertions(+), 490 deletions(-) delete mode 100755 openwrtBuild create mode 100755 openwrtbuilder create mode 100644 openwrtbuilder.code-workspace diff --git a/.gitignore b/.gitignore index dbe0b71..dc9bc52 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ sources/ bin/ files/ +patches/ .lock diff --git a/.vscode/settings.json b/.vscode/settings.json index 90fa232..d530ff1 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "window.title": "openwrtBuild", + "window.title": "openwrtbuilder", "cSpell.words": [ "infile", "isfile", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8c3dd6a..e944e88 100755 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Build RPi4 snapshot in toolbox", "type": "shell", - "command": "toolboxRun -c openwrt ${file} --version snapshot --profile rpi-4", + "command": "toolbox ${file} -p r4s -d", "problemMatcher": [] } ] diff --git a/openwrtBuild b/openwrtBuild deleted file mode 100755 index f625a37..0000000 --- a/openwrtBuild +++ /dev/null @@ -1,488 +0,0 @@ -#!/usr/bin/env bash -# -# This script/function will build and flash/upgrade OpenWRT based on user-defined custom profiles -# For Fedora/Debian/Ubuntu only -# -# MIT License -# Copyright (c) 2020 Bryan Roessler -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -printHelpAndExit() { - - debug "${FUNCNAME[0]}" - - cat <<-'EOF' -USAGE: -openwrtBuild [[OPTION] [VALUE]]... - -If PROFILE is set and TARGET is not, buildOpenwrt can use a custom profile specified in DEFAULTS - -OPTIONS - --profile, -p PROFILE - --version, -v OPENWRT_VERSION - --builddir, -b PATH - --ssh-upgrade SSH_PATH - Example: root@192.168.1.1 - --ssh-backup SSH_PATH - Enabled by default for --ssh-upgrade - --flash, -f DEVICE - Example: /dev/sdX - --debug, -d - --help, -h -EOF - # Exit using passed exit code - [[ -z $1 ]] && exit 0 || exit "$1" -} - - -setDefaults() { - - debug "${FUNCNAME[0]}" - - export _target _factory_suffix _sysupgrade_suffix _profile _builddir _debug _filesroot - declare -ag _packages - - [[ -z $_debug ]] && _debug="false" # Set to true to enable debugging by default - [[ -z $_builddir ]] && _builddir="$PWD" - [[ -z $_filesroot ]] && _filesroot="$_builddir/files/" - - # Additional packages for all profiles - _packages+=("luci" "luci-ssl" "nano" "htop" "tcpdump" "diffutils" "tar" "iperf") - - # Exit if no profile specified - [[ -z $_profile ]] && echo "You must specify a target profile (device)" && printHelpAndExit 1 - - # By default use latest release - [[ -z $_version ]] && _version="21.02.1" - - # Custom profiles - # TP-Link Archer C7v2 WAP (dumb AP) w/ legacy drivers for better performance - if [[ "$_profile" == "archer" ]]; then - _profile="tplink_archer-c7-v2" - _target="ath79/generic" - _filesystem="squashfs" - _packages+=("-dnsmasq" \ - "-odhcpd" \ - "-iptables" \ - "-ath10k-firmware-qca988x-ct" \ - "ath10k-firmware-qca988x-ct-full-htt") - # Linksys EA8300 (dumb AP) - elif [[ "$_profile" == "linksys" ]]; then - _profile="linksys_ea8300" - _target="ipq40xx/generic" - _filesystem="squashfs" - _packages+=("-dnsmasq" \ - "-odhcpd" \ - "-iptables" \ - ) - # Raspberry Pi 4B router with USB->Ethernet dongle - elif [[ "$_profile" == "rpi-4" ]]; then - _target="bcm27xx/bcm2711" - _filesystem="ext4" - _packages+=("kmod-usb-net-asix-ax88179" \ - "kmod-usb-net-rtl8152" \ - "luci-app-upnp" \ - "luci-app-wireguard" \ - "luci-app-vpn-policy-routing" \ - "-dnsmasq" \ - "dnsmasq-full" \ - "luci-app-ddns" \ - "luci-app-sqm") - # NanoPi R2S router - elif [[ "$_profile" == "r2s" ]]; then - _profile="friendlyarm_nanopi-r2s" - _target="rockchip/armv8" - _filesystem="ext4" - _packages+=("luci-app-upnp" \ - "luci-app-wireguard" \ - "luci-app-vpn-policy-routing" \ - "-dnsmasq" \ - "dnsmasq-full" \ - "luci-app-ddns" \ - "luci-app-sqm" \ - "luci-app-statistics" \ - "collectd-mod-sensors" \ - "collectd-mod-thermal" \ - "collectd-mod-conntrack" \ - "smcroute" \ - "curl" \ - "ethtool") - elif [[ "$_profile" == "r4s" ]]; then - _version="snapshot" - _profile="friendlyarm_nanopi-r4s" - _target="rockchip/armv8" - _filesystem="ext4" - _packages+=("luci-app-upnp" \ - "luci-app-wireguard" \ - "luci-app-vpn-policy-routing" \ - "-dnsmasq" \ - "dnsmasq-full" \ - "luci-app-ddns" \ - "luci-app-sqm" \ - "luci-app-statistics" \ - "collectd-mod-sensors" \ - "collectd-mod-thermal" \ - "collectd-mod-conntrack" \ - "smcroute" \ - "curl" \ - "ethtool") - fi -} - - -parseInput() { - - debug "${FUNCNAME[0]}" - - if _input=$(getopt -o +v:p:b:f:dh -l version:,profile:,builddir:,ssh-upgrade:,ssh-backup:,flash:,debug,help -- "$@"); then - eval set -- "$_input" - while true; do - case "$1" in - --version|-v) - shift && _version="$1" - ;; - --profile|-p) - shift && _profile="$1" - ;; - --builddir|-b) - shift && _builddir="$1" - ;; - --ssh-upgrade) - shift && _ssh_upgrade_path="$1" - ;; - --ssh-backup) - shift && _ssh_backup_path="$1" - ;; - --flash|-f) - shift && _flash_dev="$1" - ;; - --debug|-d) - echo "Debugging on" - _debug="true" - ;; - --help|-h) - printHelpAndExit 0 - ;; - --) - shift - break - ;; - esac - shift - done - else - echo "Incorrect options provided" - printHelpAndExit 1 - fi -} - - -debug () { [[ "$_debug" == "true" ]] && echo "Running: " "$@" ; } - - -setVars() { - - debug "${FUNCNAME[0]}" - - getOS () { - - debug "${FUNCNAME[0]}" - - if [[ -f /etc/os-release ]]; then - # shellcheck disable=SC1091 - source /etc/os-release - export ID="$ID" - echo "Detected platform: $ID" - else - echo "Cannot detect OS!" - exit 1 - fi - } - getOS - - export _source_archive="$_builddir/sources/$_profile-$_version.tar.xz" - export _source_dir="${_source_archive%.tar.xz}" - export _out_bin_dir="$_builddir/bin/$_profile-$_version/" - - export _patches_dir="$_builddir/patches/" - export _files_dir="$_builddir/files/" - - if [[ "$_version" == "snapshot" ]]; then - local _out_prefix="$_out_bin_dir/openwrt-${_target//\//-}-$_profile" - else - local _out_prefix="$_out_bin_dir/openwrt-$_version-${_target//\//-}-$_profile" - fi - - - export _factory_bin="$_out_prefix-$_filesystem-factory.bin" - export _factory_bin_fname="${_factory_bin##*/}" - export _factory_bin_gz="$_factory_bin.gz" - export _factory_bin_gz_fname="${_factory_bin_gz##*/}" - - export _sysupgrade_bin="$_out_prefix-$_filesystem-sysupgrade.bin" - export _sysupgrade_bin_fname="${_sysupgrade_bin##*/}" - export _sysupgrade_bin_gz="$_sysupgrade_bin.gz" - export _sysupgrade_bin_gz_fname="${_sysupgrade_bin_gz##*/}" -} - - -installPrerequisites() { - - debug "${FUNCNAME[0]}" - - local -a _pkg_list - local _pkg_cmd - - if [[ "$ID" == "fedora" ]]; then - _pkg_list=("@c-development" "@development-tools" "@development-libs" "perl-FindBin" "zlib-static" "elfutils-libelf-devel" "gawk" "unzip" "file" "wget" "python3" "python2" "axel") - _pkg_cmd="dnf" - elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then - _pkg_list=("build-essential" "libncurses5-dev" "libncursesw5-dev" "zlib1g-dev" "gawk" "git" "gettext" "libssl-dev" "xsltproc" "wget" "unzip" "python" "axel") - _pkg_cmd="apt-get" - fi - - echo "Installing dependencies" - debug "sudo $_pkg_cmd -y install ${_pkg_list[*]}" - if ! sudo "$_pkg_cmd" -y install "${_pkg_list[@]}" > /dev/null 2>&1; then - echo "Warning: Problem installing prerequisites" - return 1 - fi -} - - -acquireImageBuilder() { - - debug "${FUNCNAME[0]}" - - local _url _filename - - if [[ "$_version" == "snapshot" ]]; then - # Remove existing ImageBuilders - [[ -f "$_source_archive" ]] && rm "$_source_archive" - _filename="openwrt-imagebuilder-${_target//\//-}.Linux-x86_64.tar.xz" - _url="https://downloads.openwrt.org/snapshots/targets/$_target/$_filename" - else - # Reuse existing ImageBuilders - [[ -f "$_source_archive" ]] && return 0 - _filename="openwrt-imagebuilder-$_version-${_target//\//-}.Linux-x86_64.tar.xz" - _url="https://downloads.openwrt.org/releases/$_version/targets/$_target/$_filename" - fi - - # Make sources directory if it does not exist - [[ ! -d "$_builddir/sources" ]] && mkdir -p "$_builddir/sources" - - echo "Downloading image archive" - debug "axel -o $_source_archive $_url" - if ! axel -o "$_source_archive" "$_url" > /dev/null 2>&1; then - echo "Could not download Image Builder" - exit 1 - fi -} - - -extractImageBuilder() { - - debug "${FUNCNAME[0]}" - - [[ ! -d "$_source_dir" ]] && mkdir -p "$_source_dir" - - if [[ ! -f "$_source_archive" ]]; then - echo "Archive missing" - exit 1 - fi - - echo "Extracting image archive" - debug "tar -xf $_source_archive -C $_source_dir --strip-components 1" - if ! tar -xf "$_source_archive" -C "$_source_dir" --strip-components 1; then - echo "Extraction failed" - exit 1 - fi -} - - -# copyFiles() { - -# debug "${FUNCNAME[0]}" - -# declare -l _this_files_dir="$_files_dir/$_profile" - -# [[ ! -d "$_files_dir" ]] && return - -# $_profile == "r2s" - - -# } - - -makeImage() { - - debug "${FUNCNAME[0]}" - - # move to extracted source directory - if ! pushd "$_source_dir" > /dev/null 2>&1; then - exit 1 - fi - - # Make bin dir - [[ ! -d "$_out_bin_dir" ]] && mkdir -p "$_out_bin_dir" - - # build image - echo "Running make -j4 image BIN_DIR=$_out_bin_dir PROFILE=$_profile PACKAGES=${_packages[*]} FILES=$_filesroot" - debug "make -j4 image BIN_DIR=$_out_bin_dir PROFILE=$_profile PACKAGES=${_packages[*]} FILES=$_filesroot > make.log" - if ! make image BIN_DIR="$_out_bin_dir" PROFILE="$_profile" PACKAGES="${_packages[*]}" FILES="$_filesroot" > make.log; then - echo "Make image failed!" - exit 1 - fi - - if ! popd > /dev/null 2>&1; then - exit 1 - fi -} - - -extractImage() { - - debug "${FUNCNAME[0]}" "$@" - - local _gz - - [[ $# -lt 1 ]] && echo "extractImage() requires at least one argument" && exit 1 - - for _gz in "$@"; do - [[ ! -f "$_gz" ]] && return 1 - debug "gunzip -qfk $_gz" - if ! gunzip -qfk "$_gz"; then - echo "$_gz extraction failed!" - fi - done -} - - -flashImage() { - - debug "${FUNCNAME[0]}" - - if [[ -z $_factory_bin && -f "$_factory_bin_gz" ]]; then - extractImage "$_factory_bin_gz" - fi - - if [[ ! -e "$_flash_dev" ]]; then - echo "The device specified by --flash could not be found" - exit 1 - fi - - echo "Unmounting target device $_flash_dev partitions" - debug "umount $_flash_dev?*" - sudo umount "$_flash_dev"?* - - debug "sudo dd if=\"$_factory_bin\" of=\"$_flash_dev\" bs=2M conv=fsync" - if sudo dd if="$_factory_bin" of="$_flash_dev" bs=2M conv=fsync; then - sync - echo "Image flashed sucessfully!" - else - echo "dd failed!" - exit 1 - fi -} - - -sshBackup() { - - debug "${FUNCNAME[0]}" - - local _source="$1" - local _random="$RANDOM" - - if ! ssh -t "$_source" "sysupgrade -b /tmp/backup-${_random}.tar.gz"; then - echo "SSH backup failed" - exit 1 - fi - if ! scp "$_source":/tmp/backup-"${_random}".tar.gz "$_builddir"; then - echo "Could not copy SSH backup" - exit 1 - fi - - if ! ssh -t "$_source" "rm -f /tmp/backup-${_random}.tar.gz"; then - echo "Could not remove /tmp/backup-${_random}.tar.gz from $_source" - fi - - [[ -d "$_filesroot" ]] && rm -rf "$_filesroot" - mkdir -p "$_filesroot" - - if ! tar xzf "$_builddir/backup-${_random}.tar.gz" etc/ -C "$_filesroot"; then - "Could not extract SSH backup" - exit 1 - fi - - rm "$_builddir/backup-${_random}.tar.gz" - -} - - -sshUpgrade() { - - debug "${FUNCNAME[0]}" - - if [[ -f "$_sysupgrade_bin_gz" ]]; then - local _source="$_sysupgrade_bin_gz" - local _source_fname="$_sysupgrade_bin_gz_fname" - elif [[ -f "$_sysupgrade_bin" ]]; then - local _source="$_sysupgrade_bin" - local _source_fname="$_sysupgrade_bin_fname" - else - echo "Could not find upgrade file" - exit 1 - fi - - echo "Copying \"$_source\" to $_ssh_upgrade_path/tmp/" - debug "scp \"$_source\" \"$_ssh_upgrade_path\":\"/tmp/$_source_fname\"" - # shellcheck disable=SC2140 - if ! scp "$_source" "$_ssh_upgrade_path":"/tmp/$_source_fname"; then - echo "Could not access the --ssh-upgrade PATH" - exit 1 - fi - - echo "Executing remote sysupgrade" - debug "ssh \"$_ssh_upgrade_path\" \"sysupgrade -F /tmp/$_source_fname\"" - # shellcheck disable=SC2029 - ssh "$_ssh_upgrade_path" "sysupgrade -F /tmp/$_source_fname" -} - - - - -__main() { - - parseInput "$@" - setDefaults - setVars - installPrerequisites - acquireImageBuilder - extractImageBuilder - #copyFiles - rm -rf "$_ssh_backup_path" - [[ -v _ssh_backup_path ]] && sshBackup "$_ssh_backup_path" - if makeImage; then - [[ -v _ssh_upgrade_path ]] && sshUpgrade - [[ -v _flash_dev ]] && flashImage - fi -} - -__main "$@" -exit $? diff --git a/openwrtbuilder b/openwrtbuilder new file mode 100755 index 0000000..7ce349b --- /dev/null +++ b/openwrtbuilder @@ -0,0 +1,517 @@ +#!/usr/bin/env bash +# +# Build and flash/upgrade OpenWRT devices +# +# Apache 2.0 License + +printHelpAndExit() { + + debug "${FUNCNAME[0]}" + + cat <<-'EOF' +USAGE: +openwrtbuilder [[OPTION] [VALUE]]... + +If PROFILE is set and TARGET is not, openwrtbuild can use a custom profile specified in DEFAULTS + +OPTIONS + --profile, -p PROFILE + --profile-info, -i PROFILE + --list-profiles, -l + --release, -r RELEASE + --builddir, -b PATH + --ssh-upgrade HOST + Example: root@192.168.1.1 + --ssh-backup SSH_PATH + Enabled by default for --ssh-upgrade + --flash, -f DEVICE + Example: /dev/sdX + --debug, -d + --help, -h +EOF + # Exit using passed exit code + [[ -z $1 ]] && exit 0 || exit "$1" +} + + +input() { + + debug "${FUNCNAME[0]}" + + if _input=$(getopt -o +v:p:i:lb:f:dh -l release:,profile:,profile-info:,list-profiles,builddir:,ssh-upgrade:,ssh-backup:,flash:,debug,help -- "$@"); then + eval set -- "$_input" + while true; do + case "$1" in + --release|-r) + shift && RELEASE="$1" + ;; + --profile|-p) + shift && PROFILE="$1" + ;; + --profile-info|-i) + shift && profileInfo "$1" && exit $? + ;; + --list-profile|-l) + listProfiles && exit $? + ;; + --builddir|-b) + shift && BUILDDIR="$1" + ;; + --ssh-upgrade) + shift && SSH_UPGRADE_PATH="$1" + ;; + --ssh-backup) + shift && SSH_BACKUP_PATH="$1" + ;; + --flash|-f) + shift && flash_dev="$1" + ;; + --debug|-d) + echo "Debugging on" + DEBUG=true + ;; + --help|-h) + printHelpAndExit 0 + ;; + --) + shift + break + ;; + esac + shift + done + else + echo "Incorrect options provided" + printHelpAndExit 1 + fi +} + + +profiles() { + + debug "${FUNCNAME[0]}" + + [[ -z $DEBUG ]] && DEBUG=false # Set to true to enable debugging by default + [[ -z $BUILDDIR ]] && BUILDDIR="$PWD" + [[ -z $FILESDIR ]] && FILESDIR="$BUILDDIR/files/" + + # Additional packages to install for all profiles + default_packages="\ + luci \ + luci-ssl \ + nano \ + htop \ + tcpdump \ + diffutils \ + tar \ + iperf " + + # Set the default release + [[ -z $RELEASE ]] && RELEASE="21.02.1" + + # Use these tools to add and parse profiles + declare -ag PROFILES + add_profile() { + declare -Ag "$1" + PROFILES+=("$1") + } + + add_profile archer + archer['profile']="tplink_archer-c7-v2" + archer['target']="ath79/generic" + archer['filesystem']="squashfs" + archer['packages']="\ + $default_packages \ + -dnsmasq \ + -odhcpd \ + -iptables \ + -ath10k-firmware-qca988x-ct \ + ath10k-firmware-qca988x-ct-full-htt" + + add_profile linksys + linksys['profile']="linksys_ea8300" + linksys['target']="ipq40xx/generic" + linksys['filesystem']="squashfs" + linksys['packages']="\ + $default_packages \ + -dnsmasq \ + -odhcpd \ + -iptables" + + add_profile rpi4 + rpi4['profile']="rpi-4" + rpi4['target']="bcm27xx/bcm2711" + rpi4['filesystem']="ext4" + rpi4['packages']="\ + $default_packages \ + kmod-usb-net-asix-ax88179 \ + kmod-usb-net-rtl8152 \ + luci-app-upnp \ + luci-app-wireguard \ + luci-app-vpn-policy-routing \ + -dnsmasq \ + dnsmasq-full \ + luci-app-ddns \ + luci-app-sqm" + + add_profile r2s + r2s['profile']="friendlyarm_nanopi-r2s" + r2s['target']="rockchip/armv8" + r2s['filesystem']="ext4" + r2s['packages']="\ + $default_packages \ + luci-app-upnp \ + luci-app-wireguard \ + luci-app-vpn-policy-routing \ + -dnsmasq \ + dnsmasq-full \ + luci-app-ddns \ + luci-app-sqm \ + luci-app-statistics \ + collectd-mod-sensors \ + collectd-mod-thermal \ + collectd-mod-conntrack \ + smcroute \ + curl \ + ethtool" + + add_profile r4s + r4s['release']="snapshot" + r4s['profile']="friendlyarm_nanopi-r4s" + r4s['target']="rockchip/armv8" + r4s['filesystem']="ext4" + r4s['packages']="\ + $default_packages \ + luci-app-upnp \ + luci-app-wireguard \ + luci-app-vpn-policy-routing \ + -dnsmasq \ + dnsmasq-full \ + luci-app-ddns \ + luci-app-sqm \ + luci-app-statistics \ + collectd-mod-sensors \ + collectd-mod-thermal \ + collectd-mod-conntrack \ + smcroute \ + curl \ + ethtool" + + for PNAME in "${PROFILES[@]}"; do + declare -n ARR="$PNAME" + local _out_prefix + + [[ ! -v ARR['release'] ]] && ARR['release']="$RELEASE" + ARR['source_archive']="$BUILDDIR/sources/${ARR[profile]}-${ARR[release]}.tar.xz" + ARR['source_dir']="${ARR[source_archive]%.tar.xz}" + ARR['out_bin_dir']="$BUILDDIR/bin/${ARR[profile]}-${ARR[release]}" + + #_patches_dir="$BUILDDIR/patches/" + #_files_dir="$BUILDDIR/files/" + + if [[ "${ARR[release]}" == "snapshot" ]]; then + _out_prefix="${ARR[out_bin_dir]}/openwrt-${ARR[target]//\//-}-${ARR[profile]}" + else + _out_prefix="${ARR[out_bin_dir]}/openwrt-${ARR[release]}-${ARR[target]//\//-}-${ARR[profile]}" + fi + + ARR['factory_img']="$_out_prefix-${ARR[filesystem]}-factory.img" + ARR['factory_img_gz']="${ARR[factory_img]}.gz" + + ARR['sysupgrade_img']="$_out_prefix-${ARR[filesystem]}-sysupgrade.img" + ARR['sysupgrade_img_gz']="${ARR[sysupgrade_img]}.gz" + + ARR['sysupgrade_bin']="$_out_prefix-${ARR[filesystem]}-sysupgrade.bin" + ARR['sysupgrade_bin_fname']="${ARR[sysupgrade_bin]##*/}" + ARR['sysupgrade_bin_gz']="${ARR[sysupgrade_bin]}.gz" + ARR['sysupgrade_bin_gz_fname']="${ARR[sysupgrade_bin_gz]##*/}" + done +} + + +listProfiles() { + debug "${FUNCNAME[0]}" + [[ ! -v PROFILES ]] && profiles + echo "Available profiles:" + for PNAME in "${PROFILES[@]}"; do + declare -n ARR2="$PNAME" + echo "$PNAME: ${ARR2[profile]}" + done +} + + +profileInfo() { + debug "${FUNCNAME[0]}" + local _profile + _profile="$1" + [[ ! -v PROFILES ]] && profiles + declare -n ARR3="$_profile" + for i in "${!ARR3[@]}"; do + echo "$i: ${ARR3[i]}" + done +} + + +prerequisites() { + + debug "${FUNCNAME[0]}" + + local -a _pkg_list + local _pkg_cmd + + source /etc/os-release + + if [[ "$ID" == "fedora" ]]; then + _pkg_list=(\ + "@c-development" \ + "@development-tools" \ + "@development-libs" \ + "perl-FindBin" \ + "zlib-static" \ + "elfutils-libelf-devel" \ + "gawk" \ + "unzip" \ + "file" \ + "wget" \ + "python3" \ + "python2" \ + "axel" \ + ) + _pkg_cmd="dnf" + elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then + _pkg_list=(\ + "build-essential" \ + "libncurses5-dev" \ + "libncursesw5-dev" \ + "zlib1g-dev" \ + "gawk" \ + "git" \ + "gettext" \ + "libssl-dev" \ + "xsltproc" \ + "wget" \ + "unzip" \ + "python" \ + "axel" \ + ) + _pkg_cmd="apt-get" + fi + + echo "Installing dependencies" + debug "sudo $_pkg_cmd -y install ${_pkg_list[*]}" + if ! sudo "$_pkg_cmd" -y install "${_pkg_list[@]}" > /dev/null 2>&1; then + echo "Warning: Problem installing prerequisites" + return 1 + fi +} + + +getImageBuilder() { + + debug "${FUNCNAME[0]}" + + declare -n ARR4="$PROFILE" + + local _url _filename + + if [[ "${ARR4[release]}" == "snapshot" ]]; then + _filename="openwrt-imagebuilder-${ARR4[target]//\//-}.Linux-x86_64.tar.xz" + _url="https://downloads.openwrt.org/snapshots/targets/${ARR4[target]}/$_filename" + if [[ -f "${ARR4[source_archive]}" ]]; then + if askOk "Update ImageBuilder snapshot?"; then + rm -f "${ARR4[source_archive]}" + else + return 0 + fi + fi + else + _filename="openwrt-imagebuilder-${ARR4[release]}-${ARR4[target]//\//-}.Linux-x86_64.tar.xz" + _url="https://downloads.openwrt.org/releases/${ARR4[release]}/targets/${ARR4[target]}/$_filename" + [[ -f "${ARR4[source_archive]}" ]] && return 0 # Reuse existing ImageBuilders + fi + + # Make sources directory if it does not exist + [[ ! -d "$BUILDDIR/sources" ]] && mkdir -p "$BUILDDIR/sources" + + echo "Downloading imagebuilder archive" + debug "axel -o ${ARR4[source_archive]} $_url" + if ! axel -o "${ARR4[source_archive]}" "$_url" > /dev/null 2>&1; then + echo "Could not download imagebuilder archive" + exit 1 + fi + + if [[ ! -f "${ARR4[source_archive]}" ]]; then + echo "Archive missing" + exit 1 + fi + + echo "Extracting image archive" + debug "tar -xf ${ARR4[source_archive]} -C ${ARR4[source_dir]} --strip-components 1" + if ! tar -xf "${ARR4[source_archive]}" -C "${ARR4[source_dir]}" --strip-components 1; then + echo "Extraction failed" + exit 1 + fi +} + + +# copyFiles() { +# debug "${FUNCNAME[0]}" +# declare -l _this_files_dir="$_files_dir/$PROFILE" +# [[ ! -d "$_files_dir" ]] && return +# $PROFILE == "r2s" +# } + + +makeImage() { + + debug "${FUNCNAME[0]}" + + declare -n ARR5="$PROFILE" + + # Reuse the existing output + if [[ -d "${ARR5[out_bin_dir]}" ]]; then + if askOk "${ARR5[out_bin_dir]} exists. Rebuild?"; then + rm -rf "${ARR5[out_bin_dir]}" + else + return 0 + fi + fi + + [[ ! -d "${ARR5[out_bin_dir]}" ]] && mkdir -p "${ARR5[out_bin_dir]}" + + # build image + echo "Running make -j4 image BIN_DIR=${ARR5[out_bin_dir]} PROFILE=${ARR5[profile]} PACKAGES=${ARR5[packages]} FILES=$FILESDIR" + debug "make -j4 image BIN_DIR=${ARR5[out_bin_dir]} PROFILE=${ARR5[profile]} PACKAGES=${ARR5[packages]} FILES=$FILESDIR --directory=${ARR5[source_dir]} > make.log" + if ! make image BIN_DIR="${ARR5[out_bin_dir]}" PROFILE="${ARR5[profile]}" PACKAGES="${ARR5[packages]}" FILES="$FILESDIR" --directory="${ARR5[source_dir]}" > make.log; then + echo "Make image failed!" + exit 1 + fi +} + + +flashImage() { + + debug "${FUNCNAME[0]}" + + declare -n ARR6="$PROFILE" + + local _umount + + if [[ ! -e "$flash_dev" ]]; then + echo "The device specified by --flash could not be found" + exit 1 + fi + + # TODO Roughly chooses the correct image + if [[ -f "${ARR6[factory_img_gz]}" ]]; then + img_gz="${ARR6[factory_img_gz]}" + img="${ARR6[factory_img]}" + elif [[ -f "${ARR6[sysupgrade_img_gz]}" ]]; then + img_gz="${ARR6[sysupgrade_img_gz]}" + img="${ARR6[sysupgrade_img]}" + else + return 1 + fi + + debug "$img_gz $img" + + debug "gunzip -qfk $img_gz" + gunzip -qfk "$img_gz" + + echo "Unmounting target device $flash_dev partitions" + _umount=( "$flash_dev"?* ) + debug "umount ${_umount[*]}" + sudo umount "${_umount[@]}" + + debug "sudo dd if=\"$img\" of=\"$flash_dev\" bs=2M conv=fsync" + if sudo dd if="$img" of="$flash_dev" bs=2M conv=fsync; then + sync + echo "Image flashed sucessfully!" + else + echo "dd failed!" + exit 1 + fi +} + + +sshBackup() { + + debug "${FUNCNAME[0]}" + + local _random="$RANDOM" + + if ! ssh -t "$SSH_BACKUP_PATH" "sysupgrade -b /tmp/backup-${_random}.tar.gz"; then + echo "SSH backup failed" + exit 1 + fi + if ! scp "$SSH_BACKUP_PATH":/tmp/backup-"${_random}".tar.gz "$BUILDDIR"; then + echo "Could not copy SSH backup" + exit 1 + fi + + if ! ssh -t "$SSH_BACKUP_PATH" "rm -f /tmp/backup-${_random}.tar.gz"; then + echo "Could not remove /tmp/backup-${_random}.tar.gz from $SSH_BACKUP_PATH" + fi + + [[ -d "$FILESDIR" ]] && rm -rf "$FILESDIR" + mkdir -p "$FILESDIR" + + if ! tar xzf "$BUILDDIR/backup-${_random}.tar.gz" etc/ -C "$FILESDIR"; then + "Could not extract SSH backup" + exit 1 + fi + + rm "$BUILDDIR/backup-${_random}.tar.gz" + +} + + +sshUpgrade() { + + debug "${FUNCNAME[0]}" + + declare -n ARR7="$PROFILE" + + echo "Copying \"${ARR7[sysupgrade_bin_gz]}\" to $SSH_UPGRADE_PATH/tmp/" + debug "scp \"${ARR7[sysupgrade_bin_gz]}\" \"$SSH_UPGRADE_PATH\":\"/tmp/${ARR7[sysupgrade_bin_gz_fname]}\"" + # shellcheck disable=SC2140 + if ! scp "${ARR7[sysupgrade_bin_gz]}" "$SSH_UPGRADE_PATH":"/tmp/${ARR7[sysupgrade_bin_gz_fname]}"; then + echo "Could not access the --ssh-upgrade PATH" + exit 1 + fi + + echo "Executing remote sysupgrade" + debug "ssh \"$SSH_UPGRADE_PATH\" \"sysupgrade -F /tmp/${ARR7[sysupgrade_bin_gz_fname]}\"" + # shellcheck disable=SC2029 + ssh "$SSH_UPGRADE_PATH" "sysupgrade -F /tmp/${ARR7[sysupgrade_bin_gz_fname]}" +} + + +debug() { "$DEBUG" && echo "Running: " "$@" ; } + + +askOk() { + local _response + read -r -p "$* [y/N]" _response + _response=${_response,,} + [[ ! "$_response" =~ ^(yes|y)$ ]] && return 1 + return 0 +} + + +main() { + + input "$@" + profiles + prerequisites + getImageBuilder + copyFiles + [[ -v SSH_BACKUP_PATH ]] && sshBackup + if makeImage; then + [[ -v SSH_UPGRADE_PATH ]] && sshUpgrade + [[ -v flash_dev ]] && flashImage + fi +} + +main "$@" +exit $? diff --git a/openwrtbuilder.code-workspace b/openwrtbuilder.code-workspace new file mode 100644 index 0000000..1d05d6f --- /dev/null +++ b/openwrtbuilder.code-workspace @@ -0,0 +1,13 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "window.title": "openwrtbuilder", + "cSpell.words": [ + "padx" + ] + } +} \ No newline at end of file