openwrtbuilder 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. #!/usr/bin/env bash
  2. #
  3. # Copyright 2022-23 Bryan C. Roessler
  4. #
  5. # Build and deploy OpenWRT images
  6. #
  7. # Apache 2.0 License
  8. #
  9. # See README.md and ./profiles
  10. #
  11. # This will install a lot of system dependencies by default so I
  12. # recommend running it in `toolbox`, container, or VM
  13. #
  14. # Some PROFILE options are incompatible with Image Builder mode (kopts) and
  15. # will be ignored
  16. #
  17. # Set default release
  18. : "${RELEASE:="22.03.3"}"
  19. printHelp() {
  20. debug "${FUNCNAME[0]}"
  21. cat <<-'EOF'
  22. Build and deploy OpenWRT images
  23. USAGE:
  24. openwrtbuilder [OPTION [VALUE]]... -p PROFILE [-p PROFILE]...
  25. OPTIONS
  26. --profile,-p PROFILE
  27. --release,-r,--version,-v RELEASE ("snapshot", "22.03.3")
  28. --buildroot,-b PATH
  29. Default: location of openwrtbuilder script
  30. --source
  31. Build image from source, not from Image Builder
  32. --ssh-upgrade HOST
  33. Examples: root@192.168.1.1, root@router.lan
  34. --ssh-backup SSH_PATH
  35. Enabled by default for --ssh-upgrade
  36. --flash,-f DEVICE
  37. Example: /dev/sdX
  38. --reset
  39. Cleanup all source and output files
  40. --debug,-d
  41. --help,-h
  42. EXAMPLES
  43. ./openwrtbuilder -p r4s -r snapshot --debug
  44. ./openwrtbuilder -p ax6000_stock -r 23.03.3 --source --debug
  45. ./openwrtbuilder -p rpi4 -r 23.03.3 --flash /dev/sdX
  46. ./openwrtbuilder -p linksys -r snapshot --ssh-upgrade root@192.168.1.1
  47. EOF
  48. }
  49. init() {
  50. debug "${FUNCNAME[0]}"
  51. declare -g ID RPM_MGR SCRIPTDIR DL_TOOL
  52. debug || echo "To enable debugging output, use --debug or -d"
  53. # Save the script directory
  54. # https://stackoverflow.com/a/4774063
  55. SCRIPTDIR="$(cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit $? ; pwd -P)"
  56. if [[ -e "/etc/os-release" ]]; then
  57. source "/etc/os-release"
  58. else
  59. err "/etc/os-release not found"
  60. err "Your OS is unsupported"
  61. printHelp
  62. exit 1
  63. fi
  64. debug "Detected host platform: $ID"
  65. # normalize distro ID
  66. case "$ID" in
  67. debian|arch)
  68. ;;
  69. centos|fedora)
  70. if hash dnf &>/dev/null; then
  71. RPM_MGR="dnf"
  72. elif hash yum &>/dev/null; then
  73. RPM_MGR="yum"
  74. fi
  75. ;;
  76. rhel)
  77. ID="centos"
  78. ;;
  79. linuxmint|neon|*ubuntu*)
  80. ID="ubuntu"
  81. ;;
  82. *suse*)
  83. ID="suse"
  84. ;;
  85. raspbian)
  86. ID="debian"
  87. ;;
  88. *)
  89. echo "Autodetecting distro, this may be unreliable"
  90. if hash dnf &>/dev/null; then
  91. ID="fedora"
  92. RPM_MGR="dnf"
  93. elif hash yum &>/dev/null; then
  94. ID="centos"
  95. RPM_MGR="yum"
  96. elif hash apt &>/dev/null; then
  97. ID="ubuntu"
  98. elif hash pacman &>/dev/null; then
  99. ID="arch"
  100. else
  101. return 1
  102. fi
  103. ;;
  104. esac
  105. debug "Using host platform: $ID"
  106. # Set distro-specific functions
  107. case "$ID" in
  108. fedora|centos)
  109. pkg_install(){ sudo "$RPM_MGR" install -y "$@"; }
  110. ;;
  111. debian|ubuntu)
  112. pkg_install(){ sudo apt-get install -y -q0 "$@"; }
  113. ;;
  114. suse)
  115. pkg_install(){ sudo zypper --non-interactive -q install --force --no-confirm "$@"; }
  116. ;;
  117. arch)
  118. pkg_install(){ sudo pacman -S --noconfirm --needed "$@"; }
  119. ;;
  120. esac
  121. if hash axel &>/dev/null; then
  122. DL_TOOL="axel"
  123. elif hash curl &>/dev/null; then
  124. DL_TOOL="curl"
  125. else
  126. echo "Downloading the Image Builder requires axel or curl!"
  127. return 1
  128. fi
  129. }
  130. readInput() {
  131. debug "${FUNCNAME[0]}"
  132. unset RESET
  133. declare -ga PROFILES
  134. declare long_opts='release:,version:,profile:,buildroot:,source,'
  135. long_opts+='ssh-upgrade:,ssh-backup:,flash:,reset,debug,help'
  136. if _input=$(getopt -o +r:v:p:b:sf:dh -l $long_opts -- "$@"); then
  137. eval set -- "$_input"
  138. while true; do
  139. case "$1" in
  140. --release|-r|--version|-v)
  141. shift && declare -g USER_RELEASE="$1"
  142. ;;
  143. --profile|-p)
  144. shift && PROFILES+=("$1")
  145. ;;
  146. --buildroot|-b)
  147. shift && BUILDROOT="$1"
  148. ;;
  149. --source|-s)
  150. FROM_SOURCE=1
  151. ;;
  152. --ssh-upgrade)
  153. shift && SSH_UPGRADE_PATH="$1"
  154. ;;
  155. --ssh-backup)
  156. shift && SSH_BACKUP_PATH="$1"
  157. ;;
  158. --flash|-f)
  159. shift && FLASH_DEV="$1"
  160. ;;
  161. --reset)
  162. RESET=1
  163. ;;
  164. --debug|-d)
  165. echo "Debugging on"
  166. DEBUG=1
  167. ;;
  168. --help|-h)
  169. printHelp && exit 0
  170. ;;
  171. --)
  172. shift
  173. break
  174. ;;
  175. esac
  176. shift
  177. done
  178. else
  179. echo "Incorrect options provided"
  180. printHelp && exit 1
  181. fi
  182. }
  183. installDependencies() {
  184. debug "${FUNCNAME[0]}"
  185. declare -a pkg_list
  186. # TODO please contribute your platform here
  187. if (( FROM_SOURCE )); then
  188. # For building from source with make
  189. # https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem
  190. case "$ID" in
  191. fedora|centos)
  192. pkg_list+=(
  193. "bash-completion"
  194. "bzip2"
  195. "gcc"
  196. "gcc-c++"
  197. "git"
  198. "make"
  199. "ncurses-devel"
  200. "patch"
  201. "rsync"
  202. "tar"
  203. "unzip"
  204. "wget"
  205. "which"
  206. "diffutils"
  207. "python2"
  208. "python3"
  209. "perl-base"
  210. "perl-Data-Dumper"
  211. "perl-File-Compare"
  212. "perl-File-Copy"
  213. "perl-FindBin"
  214. "perl-Thread-Queue"
  215. "clang" # for qosify
  216. )
  217. ;;
  218. debian|ubuntu)
  219. pkg_list+=(
  220. "build-essential"
  221. "clang"
  222. "flex"
  223. "g++"
  224. "gawk"
  225. "gcc-multilib"
  226. "gettext"
  227. "git"
  228. "libncurses5-dev"
  229. "libssl-dev"
  230. "python3-distutils"
  231. "rsync"
  232. "unzip"
  233. "zlib1g-dev"
  234. "file"
  235. "wget"
  236. )
  237. ;;
  238. arch)
  239. pkg_list+=(
  240. "base-devel"
  241. "autoconf"
  242. "automake"
  243. "bash"
  244. "binutils"
  245. "bison"
  246. "bzip2"
  247. "clang"
  248. "fakeroot"
  249. "file"
  250. "findutils"
  251. "flex"
  252. "gawk"
  253. "gcc"
  254. "gettext"
  255. "git"
  256. "grep"
  257. "groff"
  258. "gzip"
  259. "libelf"
  260. "libtool"
  261. "libxslt"
  262. "m4"
  263. "make"
  264. "ncurses"
  265. "openssl"
  266. "patch"
  267. "pkgconf"
  268. "python"
  269. "rsync"
  270. "sed"
  271. "texinfo"
  272. "time"
  273. "unzip"
  274. "util-linux"
  275. "wget"
  276. "which"
  277. "zlib"
  278. )
  279. ;;
  280. *)
  281. debug "Skipping dependency install, your OS is unsupported"
  282. return 1
  283. ;;
  284. esac
  285. else
  286. # For Imagebuilder
  287. case "$ID" in
  288. fedora|centos)
  289. pkg_list+=(
  290. "@c-development"
  291. "@development-tools"
  292. "@development-libs"
  293. "perl-FindBin"
  294. "zlib-static"
  295. "elfutils-libelf-devel"
  296. "gawk"
  297. "unzip"
  298. "file"
  299. "wget"
  300. "python3"
  301. "python2"
  302. "axel"
  303. )
  304. ;;
  305. debian|ubuntu)
  306. pkg_list+=(
  307. "build-essential"
  308. "libncurses5-dev"
  309. "libncursesw5-dev"
  310. "zlib1g-dev"
  311. "gawk"
  312. "git"
  313. "gettext"
  314. "libssl-dev"
  315. "xsltproc"
  316. "wget"
  317. "unzip"
  318. "python"
  319. "axel"
  320. )
  321. ;;
  322. *)
  323. debug "Skipping dependency install, your OS is unsupported"
  324. return 1
  325. ;;
  326. esac
  327. fi
  328. pkg_install "${pkg_list[@]}"
  329. }
  330. getImageBuilder() {
  331. debug "${FUNCNAME[0]}"
  332. if [[ -f "$IB_ARCHIVE" ]]; then
  333. if askOK "$IB_ARCHIVE exists. Re-download?"; then
  334. rm -f "$IB_ARCHIVE"
  335. else
  336. return 0
  337. fi
  338. fi
  339. echo "Downloading Image Builder archive using $DL_TOOL"
  340. debug "$DL_TOOL -o $IB_ARCHIVE $IB_URL"
  341. "$DL_TOOL" -o "$IB_ARCHIVE" "$IB_URL"
  342. }
  343. getImageBuilderChecksum() {
  344. debug "${FUNCNAME[0]}"
  345. if [[ -f $IB_SHA256_FILE ]]; then
  346. if askOk "$IB_SHA256_FILE exists. Re-download?"; then
  347. rm -f "$IB_SHA256_FILE"
  348. else
  349. return 0
  350. fi
  351. fi
  352. debug "$DL_TOOL -o $IB_SHA256_FILE $IB_SHA256_URL"
  353. "$DL_TOOL" -o "$IB_SHA256_FILE" "$IB_SHA256_URL"
  354. }
  355. extractImageBuilder() {
  356. debug "${FUNCNAME[0]}"
  357. echo "Extracting Image Builder archive"
  358. debug "tar -xf $IB_ARCHIVE -C $BUILDDIR --strip-components 1"
  359. if ! tar -xf "$IB_ARCHIVE" -C "$BUILDDIR" --strip-components 1; then
  360. echo "Extraction failed"
  361. return 1
  362. fi
  363. }
  364. addRepos() {
  365. debug "${FUNCNAME[0]}"
  366. if [[ -v P_ARR[repo] ]]; then
  367. if ! grep -q "${P_ARR[repo]}" "$BUILDDIR/repositories.conf"; then
  368. echo "${P_ARR[repo]}" >> "$BUILDDIR/repositories.conf"
  369. fi
  370. sed -i '/option check_signature/d' "$BUILDDIR/repositories.conf"
  371. fi
  372. }
  373. sshBackup() {
  374. debug "${FUNCNAME[0]}"
  375. local _date _hostname _backup_fname
  376. [[ -d "$FILESDIR" ]] || mkdir -p "$FILESDIR"
  377. printf -v _date '%(%Y-%m-%d-%H-%M-%S)T'
  378. _hostname=$(ssh -qt "$SSH_BACKUP_PATH" echo -n \$HOSTNAME)
  379. _backup_fname="backup-$_hostname-$_date.tar.gz"
  380. # Make backup archive on remote
  381. debug "ssh -t $SSH_BACKUP_PATH sysupgrade -b /tmp/$_backup_fname"
  382. if ! ssh -t "$SSH_BACKUP_PATH" "sysupgrade -b /tmp/$_backup_fname"; then
  383. echo "SSH backup failed"
  384. exit 1
  385. fi
  386. # Move backup archive locally
  387. debug "rsync -avz --remove-source-files $SSH_BACKUP_PATH:/tmp/$_backup_fname $BUILDDIR/"
  388. if ! rsync -avz --remove-source-files \
  389. "$SSH_BACKUP_PATH":"/tmp/$_backup_fname" "$BUILDDIR/"; then
  390. echo "Could not copy SSH backup"
  391. exit 1
  392. fi
  393. # Extract backup archive
  394. debug "tar -C $FILESDIR -xzf $BUILDDIR/$_backup_fname"
  395. if ! tar -C "$FILESDIR" -xzf "$BUILDDIR/$_backup_fname"; then
  396. echo "Could not extract SSH backup"
  397. exit 1
  398. fi
  399. rm "$BUILDDIR/$_backup_fname"
  400. }
  401. makeImages() {
  402. debug "${FUNCNAME[0]}"
  403. # Reuse the existing output
  404. if [[ -d "$THIS_BINDIR" ]]; then
  405. if askOk "$THIS_BINDIR exists. Rebuild?"; then
  406. rm -rf "$THIS_BINDIR"
  407. else
  408. return 0
  409. fi
  410. fi
  411. make image \
  412. BIN_DIR="$THIS_BINDIR" \
  413. PROFILE="${P_ARR[profile]}" \
  414. PACKAGES="${P_ARR[packages]:+"${P_ARR[packages]}"}" \
  415. FILES="${FILESDIR}" \
  416. --directory="$BUILDDIR" \
  417. --jobs="$(nproc)" \
  418. > "$BUILDDIR/make.log"
  419. }
  420. verifyImages() {
  421. debug "${FUNCNAME[0]}"
  422. declare outfile
  423. for outfile in "$THIS_BINDIR"/*.img.gz; do
  424. verify "$outfile" "$IB_OUT_SHA256_FILE" || return 1
  425. done
  426. }
  427. flashImage() {
  428. debug "${FUNCNAME[0]}"
  429. declare img img_gz partitions
  430. if [[ ! -e "$FLASH_DEV" ]]; then
  431. echo "The device specified by --flash could not be found"
  432. exit 1
  433. fi
  434. # TODO Roughly choose the correct image
  435. if (( FROM_SOURCE )); then
  436. if [[ -f $SOURCEFACTORYIMGGZ &&
  437. -f $SOURCESYSUPGRADEIMGGZ ]]; then
  438. local _response
  439. echo "$SOURCEFACTORYIMGGZ and $SOURCESYSUPGRADEIMGGZ both exist"
  440. read -r -p "Flash factory or sysupgrade image? [(f)actory/(s)ysupgrade]" _response
  441. _response=${_response,,}
  442. if [[ "$_response" =~ ^(f|factory)$ ]]; then
  443. img_gz="$SOURCEFACTORYIMGGZ"
  444. img="$SOURCEFACTORYIMG"
  445. elif [[ "$_response" =~ ^(s|sysupgrade)$ ]]; then
  446. img_gz="$SOURCESYSUPGRADEIMGGZ"
  447. img="$SOURCESYSUPGRADEIMG"
  448. else
  449. echo "Invalid input, you must enter f or s"
  450. fi
  451. elif [[ -f $SOURCEFACTORYIMGGZ ]]; then
  452. img_gz="$SOURCEFACTORYIMGGZ"
  453. img="$SOURCEFACTORYIMG"
  454. elif [[ -f $SOURCESYSUPGRADEIMGGZ ]]; then
  455. img_gz="$SOURCESYSUPGRADEIMGGZ"
  456. img="$SOURCESYSUPGRADEIMG"
  457. else
  458. echo "No files found at $SOURCEFACTORYIMGGZ or $SOURCESYSUPGRADEIMGGZ"
  459. echo "Check your build output"
  460. return 1
  461. fi
  462. else
  463. if [[ -f $FACTORYIMGGZ &&
  464. -f $SYSUPGRADEIMGGZ ]]; then
  465. local _response
  466. echo "$FACTORYIMGGZ and $SYSUPGRADEIMGGZ both exist"
  467. read -r -p "Flash factory or sysupgrade image? [(f)actory/(s)ysupgrade]" _response
  468. _response=${_response,,}
  469. if [[ "$_response" =~ ^(f|factory)$ ]]; then
  470. img_gz="$FACTORYIMGGZ"
  471. img="$FACTORYIMG"
  472. elif [[ "$_response" =~ ^(s|sysupgrade)$ ]]; then
  473. img_gz="$SYSUPGRADEIMGGZ"
  474. img="$SYSUPGRADEIMG"
  475. else
  476. echo "Invalid input, you must enter f or s"
  477. fi
  478. elif [[ -f $FACTORYIMGGZ ]]; then
  479. img_gz="$FACTORYIMGGZ"
  480. img="$FACTORYIMG"
  481. elif [[ -f $SYSUPGRADEIMGGZ ]]; then
  482. img_gz="$SYSUPGRADEIMGGZ"
  483. img="$SYSUPGRADEIMG"
  484. else
  485. echo "No files found at $FACTORYIMGGZ or $SYSUPGRADEIMGGZ"
  486. echo "Check your build output"
  487. return 1
  488. fi
  489. fi
  490. debug "$img_gz $img"
  491. debug "gunzip -qfk $img_gz"
  492. gunzip -qfk "$img_gz"
  493. echo "Unmounting target device $FLASH_DEV partitions"
  494. partitions=( "$FLASH_DEV"?* )
  495. debug "umount ${partitions[*]}"
  496. sudo umount "${partitions[@]}"
  497. debug "sudo dd if=$img of=$FLASH_DEV bs=2M conv=fsync"
  498. if sudo dd if="$img" of="$FLASH_DEV" bs=2M conv=fsync; then
  499. sync
  500. echo "Image flashed sucessfully!"
  501. else
  502. echo "dd failed!"
  503. exit 1
  504. fi
  505. }
  506. sshUpgrade() {
  507. debug "${FUNCNAME[0]}"
  508. declare img_gz img_fname
  509. if (( FROM_SOURCE )); then
  510. if [[ -f $SOURCESYSUPGRADEIMGGZ ]]; then
  511. img_gz="$SOURCESYSUPGRADEIMGGZ"
  512. img_fname="$SOURCESYSUPGRADEIMGGZFNAME"
  513. fi
  514. elif [[ -f $SYSUPGRADEIMGGZ ]]; then
  515. img_gz="$SYSUPGRADEIMGGZ"
  516. img_fname="$SYSUPGRADEIMGGZFNAME"
  517. fi
  518. if [[ ! -f $img_gz ]]; then
  519. echo "$img_gz is missing, check build output"
  520. return 1
  521. fi
  522. echo "Copying '$img_gz' to $SSH_UPGRADE_PATH/tmp/$img_fname"
  523. debug "scp $img_gz $SSH_UPGRADE_PATH:/tmp/$img_fname"
  524. if ! scp "$img_gz" "$SSH_UPGRADE_PATH":"/tmp/$img_fname"; then
  525. echo "Could not copy $img_gz to $SSH_UPGRADE_PATH:/tmp/$img_fname"
  526. return 1
  527. fi
  528. echo "Executing remote sysupgrade"
  529. debug "ssh $SSH_UPGRADE_PATH sysupgrade -F /tmp/$img_fname"
  530. # shellcheck disable=SC2029
  531. # execute remotely
  532. # this will probably be a weird exit code from closed connection
  533. ssh "$SSH_UPGRADE_PATH" "sysupgrade -F /tmp/$img_fname"
  534. }
  535. fromSource() {
  536. debug "${FUNCNAME[0]}"
  537. declare src_url="https://github.com/openwrt/openwrt.git"
  538. declare pkg kopt opt commit gitworktreedir seed_file
  539. declare -a make_opts config_opts
  540. echo "Building from source is under development"
  541. # Update source code
  542. if [[ ! -d "$GITSRCDIR" ]]; then
  543. mkdir -p "$GITSRCDIR"
  544. git clone "$src_url" "$GITSRCDIR"
  545. fi
  546. git -C "$GITSRCDIR" pull
  547. commit=$(git -C "$GITSRCDIR" rev-parse HEAD)
  548. debug "commit hash: $commit"
  549. if [[ $RELEASE == "snapshot" ]]; then
  550. gitworktreedir="$SRCDIR/$profile/$RELEASE"
  551. git -C "$GITSRCDIR" \
  552. worktree add \
  553. --force \
  554. --detach \
  555. "$gitworktreedir" \
  556. "master"
  557. else
  558. gitworktreedir="$SRCDIR/$profile/$RELEASE"
  559. git -C "$GITSRCDIR" \
  560. worktree add \
  561. --force \
  562. --detach \
  563. "$gitworktreedir" \
  564. "origin/openwrt-${RELEASE%.*}"
  565. fi
  566. seed_file="$gitworktreedir/.config"
  567. debug "gitworktreedir: $gitworktreedir"
  568. debug "seed_file: $seed_file"
  569. pushd "$gitworktreedir" &>/dev/null || return 1
  570. # Update package feed
  571. ./scripts/feeds update -a &&
  572. ./scripts/feeds install -a
  573. # Grab the release seed config
  574. if ! curl -so "$seed_file" "$SEED_URL"; then
  575. echo "Could not obtain $seed_file from $SEED_URL"
  576. return 1
  577. fi
  578. # Set compilation output dir
  579. config_opts+=("CONFIG_BINARY_FOLDER=\"$THIS_BINDIR\"")
  580. # Add custom packages
  581. for pkg in ${P_ARR[packages]}; do
  582. if [[ $pkg == -* ]]; then
  583. config_opts+=("CONFIG_PACKAGE_${pkg#-}=n") # remove package
  584. else
  585. config_opts+=("CONFIG_PACKAGE_$pkg=y") # add package
  586. fi
  587. done
  588. # Add kopts from profile
  589. for kopt in ${P_ARR[kopts]}; do
  590. config_opts+=("$kopt")
  591. done
  592. # Only compile selected fs
  593. sed -i '/CONFIG_TARGET_ROOTFS_/d' "$seed_file"
  594. config_opts+=("CONFIG_TARGET_PER_DEVICE_ROOTFS=n")
  595. if [[ $FILESYSTEM == "squashfs" ]]; then
  596. config_opts+=("CONFIG_TARGET_ROOTFS_EXT4FS=n")
  597. config_opts+=("CONFIG_TARGET_ROOTFS_SQUASHFS=y")
  598. elif [[ $FILESYSTEM == "ext4" ]]; then
  599. config_opts+=("CONFIG_TARGET_ROOTFS_SQUASHFS=n")
  600. config_opts+=("CONFIG_TARGET_ROOTFS_EXT4FS=y")
  601. fi
  602. # Only compile selected target
  603. sed -i '/CONFIG_TARGET_DEVICE_/d' "$seed_file"
  604. config_opts+=("CONFIG_TARGET_MULTI_PROFILE=n")
  605. config_opts+=("CONFIG_TARGET_PROFILE=DEVICE_${P_ARR[profile]}")
  606. config_opts+=("CONFIG_TARGET_${P_ARR[target]//\//_}_DEVICE_${P_ARR[profile]}=y")
  607. config_opts+=("CONFIG_SDK=n")
  608. # config_opts+=("CONFIG_SDK_LLVM_BPF=n")
  609. config_opts+=("CONFIG_IB=n")
  610. config_opts+=("CONFIG_MAKE_TOOLCHAIN=n")
  611. # Write options to config seed file
  612. for opt in "${config_opts[@]}"; do
  613. debug "Writing $opt to $seed_file"
  614. # Respect nested quotes (ex. in kopts)
  615. echo "$opt" | xargs >> "$seed_file"
  616. done
  617. # TODO for now symlink clang for qosify
  618. # declare llvm_dir="$GITSRCDIR/staging_dir/host/llvm-bpf/bin"
  619. # [[ -d "$llvm_dir" ]] || mkdir -p "$llvm_dir"
  620. # ln -fs "$(which clang)" "$llvm_dir/clang"
  621. # Make image
  622. (( DEBUG )) && make_opts+=("V=s")
  623. # Cleaning modes
  624. # make clean # compiled output
  625. # make targetclean # compiled output, toolchain
  626. # make dirclean # compiled output, toolchain, build tools
  627. # make distclean # compiled output, toolchain, build tools, .config, feeds, .ccache
  628. debug "make ${make_opts[*]} defconfig"
  629. make "${make_opts[@]}" defconfig
  630. debug "make ${make_opts[*]} targetclean"
  631. make "${make_opts[@]}" targetclean
  632. debug "make ${make_opts[*]} download"
  633. make "${make_opts[@]}" download
  634. debug "make ${make_opts[*]} -j$(nproc) world"
  635. make "${make_opts[@]}" -j"$(nproc)" world
  636. popd &>/dev/null || return 1
  637. linkSourceImage
  638. exit
  639. }
  640. # Make the output tree match Image Builder's (non-destructively)
  641. linkSourceImage() {
  642. debug "${FUNCNAME[0]}"
  643. declare out_file
  644. declare -a out_files=("$THIS_BINDIR/targets/${P_ARR[target]}/"*.{img,img.gz,ubi})
  645. for out_file in "${out_files[@]}"; do
  646. [[ -f $out_file ]] && ln -fs "$out_file" "$THIS_BINDIR/${out_file##*/}"
  647. done
  648. }
  649. debug() { (( DEBUG )) && echo "Debug: $*"; }
  650. askOk() {
  651. local _response
  652. read -r -p "$* [y/N]" _response
  653. _response=${_response,,}
  654. [[ "$_response" =~ ^(yes|y)$ ]]
  655. }
  656. resetAll() {
  657. debug "${FUNCNAME[0]}"
  658. askOk "Remove $SRCDIR and $BINDIR?" || exit $?
  659. debug "rm -rf $SRCDIR $BINDIR"
  660. rm -rf "$SRCDIR" "$BINDIR"
  661. }
  662. resetProfile() {
  663. debug "${FUNCNAME[0]}"
  664. askOk "Remove $BUILDDIR and $THIS_BINDIR?" || exit $?
  665. debug "rm -rf $BUILDDIR $THIS_BINDIR"
  666. rm -rf "$BUILDDIR" "$THIS_BINDIR"
  667. }
  668. loadProfiles() {
  669. debug "${FUNCNAME[0]}"
  670. declare -g PFILE
  671. PFILE="$SCRIPTDIR/profiles"
  672. # shellcheck source=./profiles
  673. ! source "$PFILE" && echo "profiles file missing!" && return 1
  674. }
  675. verify() {
  676. debug "${FUNCNAME[0]}"
  677. declare file_to_check="$1"
  678. declare sumfile="$2"
  679. declare checksum
  680. hash sha256sum &>/dev/null || return 1
  681. [[ -f $sumfile && -f $file_to_check ]] || return 1
  682. checksum=$(grep "${file_to_check##*/}" "$sumfile" | cut -f1 -d' ')
  683. echo -n "$checksum $file_to_check" | sha256sum --check --status
  684. }
  685. main() {
  686. debug "${FUNCNAME[0]}"
  687. init
  688. loadProfiles
  689. readInput "$@"
  690. # Fallback to SCRIPTDIR if BUILDROOT has not been set
  691. declare -g BUILDROOT="${BUILDROOT:=$SCRIPTDIR}"
  692. [[ $BUILDROOT == "/" ]] && echo "Invalid --buildroot" && exit 1
  693. declare -g FILESDIR="${FILESDIR:=$BUILDROOT/src/files}"
  694. declare -g SRCDIR="$BUILDROOT/src" # input/build
  695. declare -g BINDIR="$BUILDROOT/bin" # output
  696. declare -g GITSRCDIR="$SRCDIR/openwrt"
  697. for dir in "$SRCDIR" "$BINDIR"; do
  698. [[ -d "$dir" ]] || mkdir -p "$dir"
  699. done
  700. # Allow --reset without a profile
  701. if [[ ${#PROFILES} -lt 1 ]]; then
  702. if (( RESET )); then
  703. resetAll
  704. exit
  705. else
  706. echo "No profile supplied" && return 1
  707. fi
  708. fi
  709. installDependencies
  710. for profile in "${PROFILES[@]}"; do
  711. debug "Starting profile: $profile"
  712. if [[ ! ${!profile@a} = A ]]; then
  713. echo "Profile '$profile' does not exist"
  714. return 1
  715. fi
  716. # Store profile settings in P_ARR
  717. declare -gn P_ARR="$profile"
  718. # release precedence: user input>profile>env>hardcode
  719. declare -g RELEASE="${USER_RELEASE:=${P_ARR[release]:=$RELEASE}}"
  720. declare -g BUILDDIR="$SRCDIR/$profile/$RELEASE"
  721. declare -g FILESYSTEM="${P_ARR[filesystem]:="squashfs"}"
  722. declare -g THIS_BINDIR="$BINDIR/$profile/$RELEASE"
  723. if [[ "$RELEASE" == "snapshot" ]]; then
  724. declare url_prefix="https://downloads.openwrt.org/snapshots/targets/${P_ARR[target]}"
  725. declare url_filename="openwrt-imagebuilder-${P_ARR[target]//\//-}.Linux-x86_64.tar.xz"
  726. declare img_fname="openwrt-${P_ARR[target]//\//-}-${P_ARR[profile]}-$FILESYSTEM"
  727. else
  728. declare url_prefix="https://downloads.openwrt.org/releases/$RELEASE/targets/${P_ARR[target]}"
  729. declare url_filename="openwrt-imagebuilder-$RELEASE-${P_ARR[target]//\//-}.Linux-x86_64.tar.xz"
  730. declare img_fname="openwrt-$RELEASE-${P_ARR[target]//\//-}-${P_ARR[profile]}-$FILESYSTEM"
  731. fi
  732. declare -g IB_URL="$url_prefix/$url_filename"
  733. declare -g IB_ARCHIVE="$BUILDDIR/$url_filename"
  734. declare -g IB_SHA256_URL="$url_prefix/sha256sums"
  735. declare -g IB_SHA256_FILE="$IB_ARCHIVE.sha256sums"
  736. declare -g IB_OUT_SHA256_FILE="$THIS_BINDIR/sha256sums"
  737. declare -g FACTORYIMG="$BUILDDIR/$img_fname-factory.img"
  738. declare -g FACTORYIMGGZ="$BUILDDIR/$img_fname-factory.img.gz"
  739. declare -g FACTORYIMGGZFNAME="${FACTORYIMGGZ##*/}"
  740. declare -g SYSUPGRADEIMG="$BUILDDIR/$img_fname-sysupgrade.img"
  741. declare -g SYSUPGRADEIMGGZ="$BUILDDIR/$img_fname-sysupgrade.img.gz"
  742. declare -g SYSUPGRADEIMGGZFNAME="${SYSUPGRADEIMGGZ##*/}"
  743. declare -g SOURCEFACTORYIMG="$THIS_BINDIR/$img_fname-factory.img"
  744. declare -g SOURCEFACTORYIMGGZ="$THIS_BINDIR/$img_fname-factory.img.gz"
  745. declare -g SOURCESYSUPGRADEIMG="$THIS_BINDIR/targets/$img_fname-sysupgrade.img"
  746. declare -g SOURCESYSUPGRADEIMGGZ="$THIS_BINDIR/targets/$img_fname-sysupgrade.img.gz"
  747. declare -g SOURCESYSUPGRADEIMGGZFNAME="${SOURCESYSUPGRADEIMGGZ##*/}"
  748. declare -g SEED_URL="$url_prefix/config.buildinfo"
  749. if (( DEBUG )); then
  750. echo "Profile settings:"
  751. for x in "${!P_ARR[@]}"; do printf "%s=%s\n" "$x" "${P_ARR[$x]}"; done
  752. echo "Build settings:"
  753. cat <<- EOF
  754. ALIAS (\$profile, \$P_ARR)=$profile, $P_ARR
  755. BUILDROOT=$BUILDROOT
  756. BUILDDIR=$BUILDDIR
  757. SRCDIR=$SRCDIR
  758. BINDIR=$BINDIR
  759. GITSRCDIR=$GITSRCDIR
  760. THIS_BINDIR=$THIS_BINDIR
  761. TARGET=${P_ARR[target]}
  762. PROFILE=${P_ARR[profile]}
  763. RELEASE=$RELEASE
  764. FILESYSTEM=$FILESYSTEM
  765. IB_URL=$IB_URL
  766. IB_ARCHIVE=$IB_ARCHIVE
  767. SEED_URL=$SEED_URL
  768. IB_SHA256_URL=$IB_SHA256_URL
  769. IB_SHA256_FILE=$IB_SHA256_FILE
  770. IB_OUT_SHA256_FILE=$IB_OUT_SHA256_FILE
  771. FACTORYIMGGZ=$FACTORYIMGGZ
  772. FACTORYIMGGZFNAME=$FACTORYIMGGZFNAME
  773. SYSUPGRADEIMGGZ=$SYSUPGRADEIMGGZ
  774. SYSUPGRADEIMGGZFNAME=$SYSUPGRADEIMGGZFNAME
  775. SOURCEFACTORYIMG=$SOURCEFACTORYIMG
  776. SOURCEFACTORYIMGGZ=$SOURCEFACTORYIMGGZ
  777. SOURCESYSUPGRADEIMG=$SOURCESYSUPGRADEIMG
  778. SOURCESYSUPGRADEIMGGZ=$SOURCESYSUPGRADEIMGGZ
  779. SOURCESYSUPGRADEIMGGZFNAME=$SOURCESYSUPGRADEIMGGZFNAME
  780. EOF
  781. fi
  782. (( RESET )) && resetProfile
  783. [[ -d $BUILDDIR ]] || mkdir -p "$BUILDDIR"
  784. (( FROM_SOURCE )) && fromSource
  785. # Acquire and verify Image Builder
  786. getImageBuilder &&
  787. getImageBuilderChecksum &&
  788. verify "$IB_ARCHIVE" "$IB_SHA256_FILE" || return $?
  789. extractImageBuilder || return $?
  790. addRepos
  791. #copyFiles
  792. [[ -v SSH_BACKUP_PATH ]] && sshBackup
  793. if makeImages && verifyImages; then
  794. [[ -v SSH_UPGRADE_PATH ]] && sshUpgrade
  795. [[ -v FLASH_DEV ]] && flashImage
  796. fi
  797. done
  798. }
  799. main "$@"
  800. exit
  801. # VM setup (for testing)
  802. # sudo sgdisk -N 0 /dev/vda &&
  803. # sudo mkfs.ext4 /dev/vda1
  804. # mkdir ~/mnt
  805. # sudo mount /dev/vda1 ~/mnt
  806. # sudo chown liveuser:liveuser -R ~/mnt