openwrtBuild 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #!/usr/bin/env bash
  2. #####################
  3. ##### DEFAULTS ######
  4. #####################
  5. setDefaults() {
  6. debug "${FUNCNAME[0]}"
  7. [[ -z $_debug ]] && _debug="true" # Set to true to enable debugging by default
  8. [[ -z $_builddir ]] && _builddir="$PWD"
  9. [[ -z $_filesroot ]] && _filesroot="$_builddir/files/"
  10. # Global default packages for all profiles
  11. declare -ag _packages=("luci" "nano" "htop" "tcpdump" "diffutils")
  12. # If no profile is specified, use the TP-Link Archer C7 v2
  13. [[ -z $_profile ]] && _profile="tplink_archer-c7-v2"
  14. # Custom profiles
  15. # TP-Link Archer C7 v2 dumb AP
  16. if [[ -z $_target ]]; then
  17. if [[ "$_profile" == "tplink_archer-c7-v2" ]]; then
  18. [[ -z $_version ]] && _version="19.07.2"
  19. [[ -z $_target ]] && _target="ath79/generic"
  20. _packages+=("-dnsmasq" "-odhcpd")
  21. # Raspberry Pi 4B router with USB->Ethernet dongle
  22. elif [[ "$_profile" == "rpi-4" ]]; then
  23. [[ -z $_version ]] && _version="snapshot"
  24. [[ -z $_target ]] && _target="bcm27xx/bcm2711"
  25. _packages+=("kmod-usb-net-asix-ax88179" "luci-app-upnp" "luci-app-wireguard" \
  26. "luci-app-vpn-policy-routing" "-dnsmasq" "dnsmasq-full" "luci-app-ddns")
  27. fi
  28. fi
  29. }
  30. #####################
  31. ##### FUNCTIONS #####
  32. #####################
  33. printHelpAndExit() {
  34. debug "${FUNCNAME[0]}"
  35. cat <<-'EOF'
  36. USAGE:
  37. openwrtBuild [[OPTION] [VALUE]]...
  38. If PROFILE is set and TARGET is not, buildOpenwrt can use a custom profile specified in DEFAULTS
  39. OPTIONS
  40. --version, -v OPENWRT_VERSION
  41. --target, -t TARGET
  42. --profile, -p PROFILE
  43. --builddir, -b PATH
  44. --ssh-upgrade SSH_PATH
  45. Example: root@192.168.1.1
  46. --flash, -f DEVICE
  47. Example: /dev/sdX
  48. --debug, -d
  49. --help, -h
  50. EOF
  51. # Exit using passed exit code
  52. [[ -z $1 ]] && exit 0 || exit "$1"
  53. }
  54. parseInput() {
  55. debug "${FUNCNAME[0]}"
  56. if _input=$(getopt -o +v:t:p:b:f:dh -l version:,target:,profile:,builddir:,ssh-upgrade:,flash:,debug,help -- "$@"); then
  57. eval set -- "$_input"
  58. while true; do
  59. case "$1" in
  60. --version|-v)
  61. shift && _version="$1"
  62. ;;
  63. --target|-t)
  64. shift && _target="$1"
  65. ;;
  66. --profile|-p)
  67. shift && _profile="$1"
  68. ;;
  69. --builddir|-b)
  70. shift && _builddir="$1"
  71. ;;
  72. --ssh-upgrade)
  73. shift && _ssh_upgrade_path="$1"
  74. ;;
  75. --flash|-f)
  76. shift && _flash_dev="$1"
  77. ;;
  78. --debug|-d)
  79. echo "Debugging on"
  80. _debug="true"
  81. ;;
  82. --help|-h)
  83. _printHelpAndExit 0
  84. ;;
  85. --)
  86. shift
  87. break
  88. ;;
  89. esac
  90. shift
  91. done
  92. else
  93. echo "Incorrect options provided"
  94. printHelpAndExit 1
  95. fi
  96. }
  97. debug () { [[ "$_debug" == "true" ]] && echo "Running: " "$@" ; }
  98. setVars() {
  99. debug "${FUNCNAME[0]}"
  100. getOS () {
  101. debug "${FUNCNAME[0]}"
  102. if [[ -f /etc/os-release ]]; then
  103. source /etc/os-release
  104. export ID="$ID"
  105. echo "Detected platform: $ID"
  106. else
  107. echo "Cannot detect OS!"
  108. exit 1
  109. fi
  110. }
  111. getOS
  112. export _source_archive="$_builddir/sources/$_profile-$_version.tar.xz"
  113. export _source_dir="${_source_archive%.tar.xz}"
  114. export _out_bin_dir="$_builddir/bin/$_profile-$_version/"
  115. export _out_bin_gz="$_out_bin_dir/openwrt-${_target//\//-}-$_profile-ext4-factory.img.gz"
  116. export _out_bin="${_out_bin_gz%.gz}"
  117. }
  118. installPrerequisites() {
  119. debug "${FUNCNAME[0]}"
  120. local -a _pkg_list
  121. local _pkg_cmd
  122. if [[ "$ID" == "fedora" ]]; then
  123. _pkg_list=("@c-development" "@development-tools" "@development-libs" "zlib-static" "elfutils-libelf-devel" "gawk" "unzip" "file" "wget" "python3" "python2" "axel")
  124. _pkg_cmd="dnf"
  125. elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  126. _pkg_list=("build-essential" "libncurses5-dev" "libncursesw5-dev" "zlib1g-dev" "gawk" "git" "gettext" "libssl-dev" "xsltproc" "wget" "unzip" "python" "axel")
  127. _pkg_cmd="apt-get"
  128. fi
  129. echo "Installing dependencies"
  130. debug "sudo $_pkg_cmd -y install ${_pkg_list[*]}"
  131. if ! sudo "$_pkg_cmd" -y install "${_pkg_list[@]}" > /dev/null 2>&1; then
  132. echo "Warning: Problem installing prerequisites"
  133. return 1
  134. fi
  135. }
  136. acquireImageBuilder() {
  137. debug "${FUNCNAME[0]}"
  138. local _url _filename
  139. if [[ "$_version" == "snapshot" ]]; then
  140. _filename="openwrt-imagebuilder-${_target//\//-}.Linux-x86_64.tar.xz"
  141. _url="https://downloads.openwrt.org/snapshots/targets/$_target/$_filename"
  142. else
  143. _filename="openwrt-imagebuilder-$_version-${_target//\//-}.Linux-x86_64.tar.xz"
  144. _url="https://downloads.openwrt.org/releases/$_version/targets/$_target/$_filename"
  145. fi
  146. # Make sources directory if it does not exist
  147. [[ ! -d "$_builddir/sources" ]] && mkdir -p "$_builddir/sources"
  148. # Remove existing ImageBuilder archives
  149. [[ -f "$_source_archive" ]] && rm "$_source_archive"
  150. echo "Downloading image archive"
  151. debug "axel -o $_source_archive $_url"
  152. if ! axel -o "$_source_archive" "$_url" > /dev/null 2>&1; then
  153. echo "Could not download Image Builder"
  154. exit 1
  155. fi
  156. }
  157. extractImageBuilder() {
  158. debug "${FUNCNAME[0]}"
  159. [[ ! -d "$_source_dir" ]] && mkdir -p "$_source_dir"
  160. if [[ ! -f "$_source_archive" ]]; then
  161. echo "Archive missing"
  162. exit 1
  163. fi
  164. echo "Extracting image archive"
  165. debug "tar -xf $_source_archive -C $_source_dir --strip-components 1"
  166. if ! tar -xf "$_source_archive" -C "$_source_dir" --strip-components 1; then
  167. echo "Extraction failed"
  168. exit 1
  169. fi
  170. }
  171. makeImage() {
  172. debug "${FUNCNAME[0]}"
  173. # move to extracted source directory
  174. if ! pushd "$_source_dir" > /dev/null 2>&1; then
  175. exit 1
  176. fi
  177. # Make bin dir
  178. [[ ! -d "$_out_bin_dir" ]] && mkdir -p "$_out_bin_dir"
  179. # build image
  180. echo "Running make -j4 image BIN_DIR=$_out_bin_dir PROFILE=$_profile PACKAGES=${_packages[*]} FILES=$_filesroot"
  181. debug "make -j4 image BIN_DIR=$_out_bin_dir PROFILE=$_profile PACKAGES=${_packages[*]} FILES=$_filesroot > make.log"
  182. if ! make -j4 image BIN_DIR="$_out_bin_dir" PROFILE="$_profile" \
  183. PACKAGES="${_packages[*]}" FILES="$_filesroot" > make.log; then
  184. echo "Make image failed!"
  185. exit 1
  186. fi
  187. if ! popd > /dev/null 2>&1; then
  188. exit 1
  189. fi
  190. }
  191. extractImage() {
  192. debug "${FUNCNAME[0]}" "$@"
  193. local _gz
  194. [[ $# -lt 1 ]] && echo "extractImage() requires at least one argument" && exit 1
  195. for _gz in "$@"; do
  196. [[ ! -f "$_gz" ]] && return 1
  197. debug "gunzip -qfk $_gz"
  198. if ! gunzip -qfk "$_gz"; then
  199. echo "$_gz extraction failed!"
  200. fi
  201. done
  202. }
  203. flashImage() {
  204. debug "${FUNCNAME[0]}"
  205. extractImage "$_out_bin_gz"
  206. if [[ ! -d "$_flash_dev" ]]; then
  207. echo "The device specified by --flash could not be found"
  208. exit 1
  209. fi
  210. echo "Unmounting target device $_flash_dev partitions"
  211. debug "umount $_flash_dev?*"
  212. sudo umount "$_flash_dev?*"
  213. debug "sudo dd if=\"$_out_bin\" of=\"$_flash_dev\" bs=2M conv=fsync"
  214. if sudo dd if="$_out_bin" of="$_flash_dev" bs=2M conv=fsync; then
  215. sync
  216. echo "Image flashed sucessfully!"
  217. else
  218. echo "dd failed!"
  219. exit 1
  220. fi
  221. }
  222. sshUpgrade() {
  223. debug "${FUNCNAME[0]}"
  224. local _out_bin_gz_name="${_out_bin_gz##*/}"
  225. echo "Copying upgrade image to $_ssh_upgrade_path"
  226. debug "scp \"$_out_bin_gz\" \"$_ssh_upgrade_path:/tmp/$_out_bin_gz_name\""
  227. # shellcheck disable=SC2140
  228. if ! scp "$_out_bin_gz" "$_ssh_upgrade_path":"/tmp/$_out_bin_gz_name"; then
  229. echo "Could not access the --ssh-upgrade PATH"
  230. exit 1
  231. fi
  232. echo "Executing remote sysupgrade"
  233. debug "ssh \"$_ssh_upgrade_path\" \"sysupgrade -F /tmp/$_out_bin_gz_name\""
  234. # shellcheck disable=SC2029
  235. ssh "$_ssh_upgrade_path" "sysupgrade -F /tmp/$_out_bin_gz_name"
  236. }
  237. __main() {
  238. parseInput "$@"
  239. setDefaults
  240. setVars
  241. installPrerequisites
  242. acquireImageBuilder
  243. extractImageBuilder
  244. makeImage
  245. [[ -n $_ssh_upgrade_path ]] && sshUpgrade
  246. [[ -n $_flash_dev ]] && flashImage
  247. }
  248. __main "$@"
  249. exit $?