#!/usr/bin/env bash # Script to download and run OpenWRT image builder with some config file ############################################################################### # OpenWRT target image config defaults ############################################################################### # Default configuration (file) to use config_name="rpi-4" # Release to fetch and build (can be "snapshot") RELEASE="" # Which target CPU architecture to build image for. # See targets here: https://downloads.openwrt.org/snapshots/targets TARGET="" # What profile (platform/device) to build for this TARGET PROFILE="" FILES="" DISABLED_SERVICES="" # See https://openwrt.org/packages/ for list of all packages PACKAGES=" luci luci-app-uhttpd luci-theme-bootstrap luci-theme-openwrt luci-theme-openwrt-2020 luci-app-wireguard kmod-wireguard wireguard-tools zoneinfo-europe kmod-usb-net-rtl8150 kmod-usb-net-rtl8152 " # glob to use for searching for USB SD-card reader device dev_usb_sdcard_glob=/dev/disk/by-id/usb-Generic-*-0:0 ############################################################################### # console colors ############################################################################### if [ -t 1 ]; then c_red="\e[31m"; c_green="\e[32m"; c_yellow="\e[33m"; c_mag="\e[35m" c_cyan="\e[36m"; c_white="\e[37m"; c_ired="\e[91m"; c_igreen="\e[92m" c_iyellow="\e[93m"; c_imag="\e[95m"; c_icyan="\e[96m"; c_iwhite="\e[97m" c_igrey="\e[90m"; c_reset="\e[0m"; c_bold="\e[1m"; c_inv="\e[7m" fi echo_run() { echo -e "\$ ${c_green}$*${c_reset}"; if [ -z "${dryrun}" ]; then eval "$*"; else true; fi; } echo_run_nodry() { echo -e "\$ ${c_green}$*${c_reset}"; eval "$*"; } echo_ok() { echo -e "${c_imag}$*${c_reset}"; } echo_note() { echo -e "${c_iyellow}$*${c_reset}"; } echo_bold() { echo -e "${c_icyan}$*${c_reset}"; } echo_inv() { echo -e "${c_inv}$*${c_reset}"; } warn() { echo >&2 -e "${c_iyellow}WARNING: $*${c_reset}"; } error() { echo >&2 -e "${c_ired}ERROR: $*${c_reset}"; } die() { error "$*"; exit 1; } verb() { [ -n "${VERBOSE}" ] && echo "$*"; } ############################################################################### # ############################################################################### openwrt_url=https://downloads.openwrt.org load_config() { local name=$1 . configs/common || die "FAILED to load config from ${f}" for f in configs/${name} configs/${name}.sh; do if [ -f ${f} ]; then . "${f}" || die "FAILED to load config from ${f}" echo "Loaded config ${f}" return 0 fi done die "configuration file ${name} not found in configs" } # setup file and directory names of image builder and final image: # target_with_dash # imagebuilder_dir # image_file_base # image_tarball init_vars() { echo "Current config:" for v in RELEASE TARGET PROFILE; do printf " %-10s = %s\n" "${v}" "${!v}" [ -n "${!v}" ] || die "Config variable ${v} has no value" done target_with_dash=$(echo "${TARGET}" | tr '/' '-') if [ "${RELEASE}" = "snapshot" ]; then tarball=openwrt-imagebuilder-${target_with_dash}.Linux-x86_64.tar.xz url_path="snapshots/targets/${TARGET}/${tarball}" else tarball=openwrt-imagebuilder-${RELEASE}-${target_with_dash}.Linux-x86_64.tar.xz url_path="releases/${RELEASE}/targets/${TARGET}/${tarball}" fi imagebuilder_dir=${tarball%%.tar*} } fetch_image_builder() { echo_note "Downloading ${RELEASE} build from ${url_path}" if [ -f "${tarball}" ]; then echo_ok "${tarball} already exists, skipping fetch" else echo_run "wget ${openwrt_url}/${url_path}" || die "wget FAILED" fi if [ -d ${imagebuilder_dir} ]; then echo_ok "${imagebuilder_dir} already exists, skipping unpack" else echo_run "tar xf ${tarball}" || die "tar xf FAILED" fi } locate_files_dir() { for d in ../configs .. .; do local path=${d}/${FILES} if [ -d ${path} ]; then echo_note "Using FILES = ${path}" FILES=${path} return 0 fi done die "FAILED to locate FILES directory: ${FILES}" } image_build() { echo_inv "make image" locate_files_dir PACKAGES=$(echo "${PACKAGES}" | tr '\n' ' ') echo_run "make image PROFILE='${PROFILE}' FILES='${FILES}' PACKAGES='${PACKAGES}' DISABLED_SERVICES='${DISABLED_SERVICES}'" || die "image build FAILED" } image_builder_make_info() { echo_inv "make info" echo_run "make info" || die "image build FAILED" local file=bin/targets/${TARGET}/${image_tarball} [ -f ${file} ] && echo_run "gunzip -f ${file}" } image_write_to_sdcard() { echo_inv "Determining SD card write command" # find the USB device that holds the SD-Card: if echo_run "ls -lh ${dev_usb_sdcard_glob}"; then realdev=$(readlink -f ${dev_usb_sdcard_glob}) echo_note "Using device ${realdev}" else echo_note "No USB storage device detected:" echo_note "You will have to insert correct USB_STORAGE device in the command below" realdev="USB_STORAGE" fi image_names_gz=$(find bin/targets/${TARGET} -name '*factory.img.gz') [ -n "${image_names_gz}" ] && echo "Unzipping images" for f in ${image_names_gz}; do echo_run "gunzip -f ${f}" done echo "Finding factory images for SD card writing:" echo_run "(cd bin/targets/${TARGET} && ls -1 *factory.img)" image_names=$(find bin/targets/${TARGET} -name '*factory.img') image_tarball=$(echo "${image_names}" | head -n1) echo_note "Here are the commands for SD card write. Verify before running:" if mount | grep "${realdev}" >/dev/null; then echo_bold "sudo umount ${realdev}?" fi echo_bold "sudo dd if=${imagebuilder_dir}/${image_tarball} \\ of=${realdev} \\ bs=1M status=progress && sync" [ "${realdev}" = "USB_STORAGE" ] && \ echo "where USB_STORAGE is the USB storage device" } ############################################################################### # ############################################################################### usage() { cat </dev/null; then cd .. echo_note "Original and modified rootfs is here:" echo_run "ls -d1 ${imagebuilder_dir}/build_dir/target-*/root*" cd - >/dev/null fi if [ -d bin/targets/${TARGET} ]; then echo_run "ls -lh bin/targets/${TARGET}/" echo_note "Final images are in ${imagebuilder_dir}/bin/targets/${TARGET}" fi