#!/bin/sh INTERACTIVE=True ASK_TO_REBOOT=0 CONFIG=/boot/config.txt RED='\033[0;31m' GREEN='\033[0;32m' BOLD='\e[1m' NC='\033[0m' is_pi () { ARCH=$(dpkg --print-architecture) if [ "$ARCH" = "armhf" ] || [ "$ARCH" = "arm64" ] ; then return 0 else return 1 fi } is_pione() { if grep -q "^Revision\s*:\s*00[0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo; then return 0 elif grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[0-36][0-9a-fA-F]$" /proc/cpuinfo ; then return 0 else return 1 fi } is_pitwo() { grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]04[0-9a-fA-F]$" /proc/cpuinfo return $? } is_pizero() { grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[9cC][0-9a-fA-F]$" /proc/cpuinfo return $? } is_pifour() { grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]11[0-9a-fA-F]$" /proc/cpuinfo return $? } get_pi_type() { if is_pione; then echo 1 elif is_pitwo; then echo 2 else echo 0 fi } is_live() { grep -q "boot=live" $CMDLINE return $? } is_ssh() { if pstree -p | egrep --quiet --extended-regexp ".*sshd.*\($$\)"; then return 0 else return 1 fi } is_fkms() { if grep -q okay /proc/device-tree/soc/v3d@7ec00000/status 2> /dev/null || grep -q okay /proc/device-tree/soc/firmwarekms@7e600000/status 2> /dev/null ; then return 0 else return 1 fi } is_installed() { if [ "$(dpkg -l "$1" 2> /dev/null | tail -n 1 | cut -d ' ' -f 1)" != "ii" ]; then return 1 else return 0 fi } deb_ver () { ver=`cat /etc/debian_version | cut -d . -f 1` echo $ver } calc_wt_size() { # NOTE: it's tempting to redirect stderr to /dev/null, so supress error # output from tput. However in this case, tput detects neither stdout or # stderr is a tty and so only gives default 80, 24 values WT_HEIGHT=17 WT_WIDTH=$(tput cols) if [ -z "$WT_WIDTH" ] || [ "$WT_WIDTH" -lt 60 ]; then WT_WIDTH=80 fi if [ "$WT_WIDTH" -gt 178 ]; then WT_WIDTH=120 fi WT_MENU_HEIGHT=$(($WT_HEIGHT-7)) } set_config_var() { lua - "$1" "$2" "$3" < "$3.bak" local key=assert(arg[1]) local value=assert(arg[2]) local fn=assert(arg[3]) local file=assert(io.open(fn)) local made_change=false for line in file:lines() do if line:match("^#?%s*"..key.."=.*$") then line=key.."="..value made_change=true end print(line) end if not made_change then print(key.."="..value) end EOF mv "$3.bak" "$3" } get_web_addresses() { IP=$(hostname -I) printf " ${BOLD}*${NC} ${GREEN}$1://$(hostname).local:$2$3${NC}\n" for ip in $IP; do if expr "$ip" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; then printf " ${BOLD}*${NC} ${GREEN}$1://$ip:$2$3${NC}\n" else printf " ${BOLD}*${NC} ${GREEN}$1://[$ip]:$2$3${NC}\n" fi done } get_ip_and_port() { IP=$(hostname -I) printf " ${BOLD}*${NC} ${GREEN}$(hostname).local:$1$2${NC}\n" for ip in $IP; do if expr "$ip" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; then printf " ${BOLD}*${NC} ${GREEN}$ip:$1$2${NC}\n" else printf " ${BOLD}*${NC} ${GREEN}[$ip]:$1$2${NC}\n" fi done } do_finish() { if [ $ASK_TO_REBOOT -eq 1 ]; then whiptail --yesno "Would you like to reboot now?" 20 60 2 if [ $? -eq 0 ]; then # yes sync reboot fi fi exit 0 } get_first_user() { printf "$(getent passwd 1000 | cut -d: -f1)" } do_homebridge_update() { pstree -s $$ | grep "hb-service" > /dev/null if [ "$?" -eq 0 ]; then whiptail --title "Error" --msgbox "You cannot run this command from the Homebridge UI Terminal.\n\nPlease connect using SSH (see wiki for instructions) and try again." 20 60 1 printf "\n" return fi curl -sfL https://repo.homebridge.io/KEY.gpg | sudo gpg --dearmor | sudo tee /usr/share/keyrings/homebridge.gpg > /dev/null echo "deb [signed-by=/usr/share/keyrings/homebridge.gpg] https://repo.homebridge.io stable main" | sudo tee /etc/apt/sources.list.d/homebridge.list > /dev/null apt-get update --allow-releaseinfo-change apt-get install -y homebridge } do_restore_config() { pstree -s $$ | grep "hb-service" > /dev/null if [ "$?" -eq 0 ]; then whiptail --title "Error" --msgbox "You cannot run this command from the Homebridge UI Terminal.\n\nPlease connect using SSH (see wiki for instructions) and try again." 20 60 1 printf "\n" return fi whiptail --yesno "This will remove all custom Homebridge config, plugins and restore to the factory default. You will need to manually remove any existing connections to this instance in the iOS Home app.\n\nAre you sure you want to proceed?" 20 60 2 RET=$? if [ $RET -eq 0 ]; then apt-get purge -y homebridge do_homebridge_update fi } do_nodejs_update() { hb-service update-node exit 0 } do_install_pihole() { pstree -s $$ | grep "hb-service" > /dev/null if [ "$?" -eq 0 ]; then whiptail --title "Error" --msgbox "You must not install Pi Hole via the Homebridge UI Terminal.\n\nFor a successful installation of Pi-Hole you must be logged in using SSH (see wiki for instructions)." 20 60 1 printf "\n" return fi whiptail --title "Warning" --yesno "Installing Pi-Hole will prevent you from accessing the Homebridge UI on port 80.\n\nYou will still be able to access the Homebridge UI on port $(cat /etc/hb-ui-port) and via:\n\n* http://homebridge.local:$(cat /etc/hb-ui-port)\n* https://homebridge.local\n\nWARNING: Failing to configure Pi-Hole correctly or attempting to uninstall Pi-Hole may result in Homebridge not working correctly. You should take a backup of your Homebridge instance via the UI before proceeding.\n\nAre you sure you want to continue?" 20 60 1 RET=$? if [ $RET -eq 0 ]; then if [ -f /etc/nginx/sites-available/homebridge.local ]; then sed -i "/listen 80;/c\ # listen 80; # http IPv4 - disabled by Pi-Hole installer" /etc/nginx/sites-available/homebridge.local sed -i "/listen \[::\]:80;/c\ # listen \[::\]:80; # http IPv6 - disabled by Pi-Hole installer" /etc/nginx/sites-available/homebridge.local if systemctl is-active --quiet nginx.service; then echo "Restarting Nginx..." systemctl restart nginx fi fi printf "Starting Pi-hole installer...\n" curl -sSL https://install.pi-hole.net | bash printf "\n${BOLD}Pi-hole has been installed${NC}\n" printf "Access Pi-hole in your browser by going to:\n" get_web_addresses http 80 /admin printf "\nYou can still access the Homebridge UI by going to:\n" get_web_addresses http $(cat /etc/hb-ui-port) get_web_addresses https 443 printf "\n" exit 0 fi } do_install_adguard_home() { if [ -e /etc/systemd/system/AdGuardHome.service ]; then whiptail --title "Remove AdGuard Home" --yesno "AdGuard Home is already installed.\n\nWould you like to UNINSTALL AdGuard Home?" 20 60 1 RET=$? if [ $RET -eq 0 ]; then systemctl stop AdGuardHome systemctl disable AdGuardHome rm -rf /etc/systemd/system/AdGuardHome.service rm -rf /opt/AdGuardHome systemctl daemon-reload whiptail --title "Success" --msgbox "AdGuard Home has been uninstalled." 20 60 1 printf "\n" fi else whiptail --title "Warning" --yesno "This will install the AdGuard Home software which uses the following ports:\n\n* 3000\n\nAre you sure you want to continue?" 20 60 1 RET=$? if [ $RET -eq 0 ]; then rm -rf /tmp/adguardhome mkdir -p /tmp/adguardhome cd /tmp/adguardhome wget https://static.adguard.com/adguardhome/release/AdGuardHome_linux_armv6.tar.gz tar xvf AdGuardHome_linux_armv6.tar.gz -C /opt rm -rf /tmp/adguardhome cd /opt/AdGuardHome ./AdGuardHome -s install if [ $? -eq 0 ]; then # Complete ADGUARD_WEB=$(get_web_addresses http 3000 | sed 's/\x1b\[[0-9;]*m//g') whiptail --title "Success" --msgbox "AdGuard Home has been installed.\n\nFinish setting up AdGuard Home via:\n\n$ADGUARD_WEB" 20 60 1 printf "\n" exit 0 else whiptail --title "Error" --msgbox "AdGuard Home failed to install correctly. Review log above." 20 60 1 printf "\n" exit 0 fi fi fi } do_install_deconz() { whiptail --title "Warning" --yesno "This will install the deCONZ and Phoscon software which will use the following ports:\n\n* 4530 - Phoscon Web App\n* 4531 - WebSockets\n\nAre you sure you want to continue?" 20 60 1 RET=$? if [ $RET -eq 0 ]; then isRaspbee="0" isRaspbee2="0" do_raspbee_setup() { echo "Setting up for RaspBee..." isRaspbee="1" # Install deps apt update --allow-releaseinfo-change sudo apt install -y i2c-tools build-essential raspberrypi-kernel-headers # WiringPi (Pi4 Only) if [ is_pifour ]; then curl -o /tmp/wiringpi-latest.deb https://project-downloads.drogon.net/wiringpi-latest.deb dpkg -i /tmp/wiringpi-latest.deb rm -rf /tmp/wiringpi-latest.deb else apt install wiringpi fi # Enable UART set_config_var enable_uart 1 $CONFIG } do_raspbee2_setup() { isRaspbee2="1" do_raspbee_setup # RTC-Installation [ -d /tmp/raspbee2-rtc-master ] && rm -rf /tmp/raspbee2-rtc-master curl -o /tmp/raspbee2-rtc.zip -L# https://github.com/dresden-elektronik/raspbee2-rtc/archive/master.zip unzip /tmp/raspbee2-rtc.zip -d /tmp cd /tmp/raspbee2-rtc-master make make install cd ~ rm -rf /tmp/raspbee2-rtc-master } do_conbee_setup() { echo "Setting up for ConBee / ConBee II..." isRaspbee="0" } FUN=$(whiptail --title "Choose Device" --menu "\nPlease select the type of device you have:" 20 60 3 --cancel-button Cancel --ok-button Select \ "C1 ConBee or ConBee II" "" \ "C2 RaspBee I" "" \ "C3 RaspBee II" "" \ 3>&1 1>&2 2>&3) RET=$? if [ $RET -eq 1 ]; then return 0 elif [ $RET -eq 0 ]; then case "$FUN" in C1\ *) do_conbee_setup ;; C2\ *) do_raspbee_setup ;; C3\ *) do_raspbee2_setup ;; *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 fi # Import Phoscon public key wget -O - http://phoscon.de/apt/deconz.pub.key | sudo apt-key add - # Configure the APT repository for deCONZ # remove -beta when https://forum.phoscon.de/t/please-create-a-repo-for-debian-11-bullseye/432 is resolved sudo sh -c "echo 'deb http://phoscon.de/apt/deconz \ $(lsb_release -cs)-beta main' > \ /etc/apt/sources.list.d/deconz.list" # Update APT package list apt update --allow-releaseinfo-change # Install deCONZ apt install -y deconz # Add override service mkdir -p /etc/systemd/system/deconz.service.d cat > /etc/systemd/system/deconz.service.d/override.conf < /etc/systemd/system/vncserver-pi.service < /dev/null 2>&1 #ExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 :12 #ExecStop=/usr/bin/vncserver -kill :12 #[Install] #WantedBy=multi-user.target #EOL systemctl enable vncserver-x11-serviced.service && systemctl start vncserver-x11-serviced.service && # systemctl enable vncserver-pi.service && # systemctl start vncserver-pi.service && STATUS=enabled else return 1 fi elif [ $RET -eq 1 ]; then if is_installed realvnc-vnc-server; then systemctl disable vncserver-x11-serviced.service systemctl stop vncserver-x11-serviced.service # systemctl disable vncserver-pi.service # systemctl stop vncserver-pi.service fi STATUS=disabled else return $RET fi if [ "$STATUS" = "disabled" ]; then whiptail --title "Success" --msgbox "The VNC Server and virtual desktop have been disabled." 20 60 1 else # Complete VNC_ACCESS_URI=$(get_ip_and_port 5912 | sed 's/\x1b\[[0-9;]*m//g') whiptail --title "Success" --msgbox "The VNC Server and virtual desktop have been configured.\n\nYou can connect to the virtual desktop using the RealVNC Viewer on port 5912:\n\n$VNC_ACCESS_URI\n\nDownload RealVNC Viewer:\n\n * https://www.realvnc.com/download/viewer/" 20 60 1 fi } do_vnc } do_extra_packages() { FUN=$(whiptail --title "Homebridge Raspberry Pi Configuration Tool (hb-config)" --menu "Advanced Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ "A0 AdGuard Home" "Install / Uninstall AdGuard Home" \ "A1 Pi-hole" "Install / Reconfigure Pi-hole" \ "A2 deCONZ / Phoscon" "Install / Update to manage your ConBee or RaspBee device" \ "A3 RealVNC Server" "Enable / Disable desktop access over VNC" \ 3>&1 1>&2 2>&3) RET=$? if [ $RET -eq 1 ]; then return 0 elif [ $RET -eq 0 ]; then case "$FUN" in A0\ *) do_install_adguard_home ;; A1\ *) do_install_pihole ;; A2\ *) do_install_deconz ;; A3\ *) do_install_desktop_and_vnc ;; *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 fi } do_configure_nginx() { whiptail --title "Warning" --yesno "Using this tool will overwrite any manual changes you may have made to the Homebridge Nginx config file.\n\nAre you sure you wish to continue?" 20 60 1 RET=$? tempDir=$(mktemp -d) if [ $RET -eq 0 ]; then whiptail --title "Homebridge Raspberry Pi Configuration Tool (hb-config)" --separate-output --checklist "\nNGINX Options:" 20 80 5 --cancel-button Cancel --ok-button Save \ "1" "Listen on port 80 - http:// " 1 \ "2" "Listen on port 443 - https:// " 1 \ "3" "Redirect http:// to https:// " 0 2>$tempDir/results if [ $? -eq 0 ]; then LISTEN_ON_PORT_80=false LISTEN_ON_PORT_443=false REDIRECT_HTTP_TO_HTTPS=false while read choice do case "$choice" in 1) LISTEN_ON_PORT_80=true ;; 2) LISTEN_ON_PORT_443=true ;; 3) REDIRECT_HTTP_TO_HTTPS=true ;; *) ;; esac done < $tempDir/results NGINX_PORT_80_CONFIG="" if [ "$LISTEN_ON_PORT_80" = "true" ]; then NGINX_PORT_80_CONFIG="# http://\n listen 80; # http IPv4\n listen [::]:80; # http IPv6\n" fi NGINX_PORT_443_CONFIG="" if [ "$LISTEN_ON_PORT_443" = "true" ]; then NGINX_PORT_443_CONFIG="# https://\n listen 443 ssl http2; # https IPv4\n listen [::]:443 ssl http2; # https IPv6\n" fi NGINX_REDIRECT_HTTP_TO_HTTPS="" if [ "$REDIRECT_HTTP_TO_HTTPS" = "true" ] && [ "$LISTEN_ON_PORT_80" = "true" ]; then NGINX_PORT_80_CONFIG="" NGINX_REDIRECT_HTTP_TO_HTTPS=" server { listen 80; # http IPv4 listen [::]:80; # http IPv6 # replace the _ with your domain name if required # eg. # server_name example.com; server_name _; return 302 https://\$host\$request_uri; }" fi NGINX_TEMPLATE="# this file was generated using the hb-config tool server { $NGINX_PORT_80_CONFIG $NGINX_PORT_443_CONFIG # replace the _ with your domain name if required # eg. # server_name example.com; server_name _; # replace with your domain # path to ssl certificate file # If using Let's Encrypt replace this path with the location of the fullchain.pem file for your domain # eg. # ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate /etc/nginx/ssl/homebridge.local.crt; # path to ssl private key file # If using Let's Encrypt replace this path with the location of the privkey.pem file for your domain # eg. # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_certificate_key /etc/nginx/ssl/homebridge.local.key; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # ssl_stapling on; # ssl_stapling_verify on; # large upload size to allow for uploading 3rd party backup files client_max_body_size 2G; error_page 502 /custom_502.html; location /startup-status.json { alias /usr/share/nginx/html/status.json; } location / { proxy_pass http://127.0.0.1:$(cat /etc/hb-ui-port); proxy_http_version 1.1; proxy_buffering off; proxy_set_header Host \$host; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection \"Upgrade\"; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for; } location = /custom_502.html { root /usr/share/nginx/html; internal; } } $NGINX_REDIRECT_HTTP_TO_HTTPS " echo "$NGINX_TEMPLATE" > /etc/nginx/sites-available/homebridge.local /usr/local/sbin/nginx-homebridge-self-signed-cert systemctl enable nginx if systemctl is-active --quiet nginx.service; then echo "Restarting Nginx..." systemctl restart nginx else echo "Starting Nginx..." systemctl start nginx fi if [ $? -eq 0 ]; then whiptail --title "Success" --msgbox "NGINX has been configured successfully." 20 60 1 else whiptail --title "Error" --msgbox "An error occured while attempting to reload the NGINX config." 20 60 1 fi fi fi } do_configure_raspbian() { raspi-config } do_update() { tempDir=$(mktemp -d) scriptUrl=https://raw.githubusercontent.com/homebridge/homebridge-raspbian-image/latest/stage3_homebridge/01-homebridge/files/hb-config-new # download the update to a temporary directory scriptUrl=$scriptUrl?$(date --iso-8601) printf "Downloading hb-config update...\n$scriptUrl\n" curl -fL# $scriptUrl > $tempDir/hb-config # check the download was a success RET=$? if [ $RET -ne 0 ]; then whiptail --title "Error" --msgbox "An error occured while attempting to update the hb-config tool." 20 60 1 else # syntax check the script is a valid bash script if bash -n $tempDir/hb-config; then chmod +x $tempDir/hb-config mv $tempDir/hb-config /usr/local/sbin/hb-config whiptail --title "Success" --msgbox "The hb-config tool has been updated and will now exit.\n\nIf you like the Homebridge Raspberry Pi image please show your support by starring the project on GitHub:\n\nhttps://github.com/homebridge/homebridge-raspbian-image" 20 60 1 exit 0 else whiptail --title "Error" --msgbox "The downloaded script was corrupted and did not pass the syntax check." 20 60 1 fi fi } do_nmtui() { if systemctl is-active --quiet NetworkManager; then nmtui else whiptail --title "Error" --msgbox "These network options not available when WiFi was configured via the Raspberry Pi Imager tool.\n\nSee https://www.raspberrypi.com/documentation/computers/configuration.html#wireless-networking-command-line" 20 60 1 fi } do_about() { IMAGE_VERSION=$(cat /etc/hb-release) whiptail --title "About" --msgbox "\ This tool provides a straight-forward way of managing Homebridge on a Raspberry Pi. Although it can be run at any time, some of the options may have difficulties if you have heavily customised your installation. Image Version: $IMAGE_VERSION Homebridge - @nfarina https://github.com/homebridge/homebridge Homebridge Config UI X - @oznu https://github.com/oznu/homebridge-config-ui-x Homebridge Raspberry Pi Image - @oznu https://github.com/homebridge/homebridge-raspbian-image \ " 20 80 1 } # Everything else needs to be run as root if [ $(id -u) -ne 0 ]; then printf "Script must be run as root. Try 'sudo hb-config'\n" exit 1 fi # # Interactive use loop # if [ "$INTERACTIVE" = True ]; then [ -e $CONFIG ] || touch $CONFIG calc_wt_size while true; do if is_pi ; then FUN=$(whiptail --title "Homebridge Raspberry Pi Image Configuration Tool (hb-config)" --backtitle "$(cat /proc/device-tree/model)" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \ "1 Update Node.js" "Update Node.js to the latest LTS version" \ "2 Update Homebridge" "Update Homebridge and Node.js to the latest version" \ "3 Restore Config" "Restores the Homebridge config to the factory default" \ "4 Extra Packages" "Optional packages, eg. Pi-Hole, UniFi Controller" \ "5 Nginx Options" "Configure Homebridge Nginx settings" \ "6 Configure OS" "Open the Raspberry Pi OS Configuration Tool" \ "7 Networking" "Open the NetworkManager UI" \ "8 Update" "Update this tool to the latest version" \ "9 About" "Information about this configuration tool" \ 3>&1 1>&2 2>&3) else FUN=$(whiptail --title "Homebridge Raspberry Pi Image Configuration Tool (hb-config)" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \ "1 Update Node.js" "Update Node.js to the latest LTS version" \ "2 Update Homebridge" "Update Homebridge and Node.js to the latest version" \ "3 Restore Config" "Restores the Homebridge config to the factory default" \ "4 Extra Packages" "Optional packages, eg. Pi-Hole, UniFi Controller" \ "5 Nginx Options" "Configure Homebridge Nginx settings" \ "6 Configure OS" "Open the Raspberry Pi OS Configuration Tool" \ "7 Networking" "Open the NetworkManager UI" \ "8 Update" "Update this tool to the latest version" \ "9 About" "Information about this configuration tool" \ 3>&1 1>&2 2>&3) fi RET=$? if [ $RET -eq 1 ]; then do_finish elif [ $RET -eq 0 ]; then if is_pi ; then case "$FUN" in 1\ *) do_nodejs_update ;; 2\ *) do_homebridge_update ;; 3\ *) do_restore_config ;; 4\ *) do_extra_packages ;; 5\ *) do_configure_nginx ;; 6\ *) do_configure_raspbian ;; 7\ *) do_nmtui ;; 8\ *) do_update ;; 9\ *) do_about ;; *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 else case "$FUN" in 1\ *) do_nodejs_update ;; 2\ *) do_homebridge_update ;; 3\ *) do_restore_config ;; 4\ *) do_extra_packages ;; 5\ *) do_configure_nginx ;; 6\ *) do_configure_raspbian ;; 7\ *) do_nmtui ;; 8\ *) do_update ;; 9\ *) do_about ;; *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 fi else exit 1 fi done fi