|
|
|
#!/bin/bash
|
|
|
|
set -Eeuo pipefail
|
|
|
|
shopt -s extglob
|
|
|
|
|
|
|
|
# TODO: Add help message
|
|
|
|
# TODO: Add parameter to set $DOWNLOADS_DIR
|
|
|
|
|
|
|
|
DOWNLOADS_DIR="$HOME/Downloads/os"
|
|
|
|
URL="https://downloads.raspberrypi.org/os_list_imagingutility_v2.json"
|
|
|
|
|
|
|
|
shopt -s expand_aliases
|
|
|
|
alias fzf='fzf --height="10" --layout="reverse"'
|
|
|
|
|
|
|
|
check_available_space() {
|
|
|
|
df "$DOWNLOADS_DIR" -h --output="avail" | tail -n +2
|
|
|
|
}
|
|
|
|
|
|
|
|
list_removable_devices() {
|
|
|
|
# see https://askubuntu.com/a/168654
|
|
|
|
for device in /sys/block/*; do
|
|
|
|
info=$(udevadm info --query=property --path="$device")
|
|
|
|
if grep -q ^ID_BUS=usb <<<"$info"; then
|
|
|
|
grep DEVNAME <<<"$info" | cut -d '=' -f2
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
download() {
|
|
|
|
printf "Will download %s in %s\nDownload size: %s\nAvailable space: %s\n\n" \
|
|
|
|
"$1" "$DOWNLOADS_DIR" "$2" "$(check_available_space)"
|
|
|
|
|
|
|
|
read -rp "Continue? [Y/n]" continue
|
|
|
|
continue=${continue:-Y}
|
|
|
|
if [[ $continue =~ [yY] ]]; then
|
|
|
|
echo "Downloading..."
|
|
|
|
curl -o "$DOWNLOADS_DIR/$1" "$3"
|
|
|
|
else exit 1; fi
|
|
|
|
}
|
|
|
|
|
|
|
|
compare_checksum() {
|
|
|
|
echo "Checking sha256 hashes"
|
|
|
|
sum=$(sha256sum "$1" | cut -f 1 -d ' ')
|
|
|
|
if [ "$sum" = "$2" ]; then
|
|
|
|
echo "Checksum matches"
|
|
|
|
else
|
|
|
|
echo "Checksum doesn't match. Remove file and download again"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
extract() {
|
|
|
|
printf "Will extract %s in %s\nExtracted size: %s\nAvailable space: %s\n\n" \
|
|
|
|
"$1" "$DOWNLOADS_DIR" "$2" "$(check_available_space)"
|
|
|
|
|
|
|
|
read -rp "Continue? [Y/n]" continue
|
|
|
|
continue=${continue:-Y}
|
|
|
|
if [[ $continue =~ [yY] ]]; then
|
|
|
|
echo "Extracting..."
|
|
|
|
unxz --keep "$DOWNLOADS_DIR/$1"
|
|
|
|
else exit 1; fi
|
|
|
|
}
|
|
|
|
|
|
|
|
flash() {
|
|
|
|
sudo dd bs=4M status=progress oflag=sync if="$1" of="$2"
|
|
|
|
}
|
|
|
|
|
|
|
|
# TODO: Improve this messy filter
|
|
|
|
read -rd '' FILTER << EOF || true
|
|
|
|
(.os_list[] | select(has("url"))), (.os_list[] | select(.subitems) | .subitems[])
|
|
|
|
| select(any(.name; contains("Raspberry Pi OS")))
|
|
|
|
| {
|
|
|
|
name, url, extract_sha256, extract_size: (.extract_size / 1024 / 1024 | round),
|
|
|
|
image_download_size: (.image_download_size / 1024 / 1024 | round), release_date
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
RAW=$(curl --no-progress-meter $URL)
|
|
|
|
JSON=$(jq "$FILTER" <<<"$RAW")
|
|
|
|
|
|
|
|
printf "Select Raspberry Pi OS Version: "
|
|
|
|
IMAGE_SELECTION=$(echo "$JSON" | jq '.name' | fzf)
|
|
|
|
printf "%s\n" "$IMAGE_SELECTION"
|
|
|
|
|
|
|
|
IMAGE_SELECTION_CSV=$(echo "$JSON" \
|
|
|
|
| jq -r ". | select(.name == $IMAGE_SELECTION) | [.name, .release_date, .url, .image_download_size, .extract_size, .extract_sha256 ] | @csv" \
|
|
|
|
| tr -d '"')
|
|
|
|
|
|
|
|
declare -a SELECTION_DATA
|
|
|
|
IFS=',' read -ra SELECTION_DATA <<< "$IMAGE_SELECTION_CSV"
|
|
|
|
|
|
|
|
ARCHIVE_FILENAME=$(basename "${SELECTION_DATA[2]}")
|
|
|
|
IMG_FILENAME=$(basename "$ARCHIVE_FILENAME" .xz)
|
|
|
|
|
|
|
|
should_download=FALSE
|
|
|
|
should_extract=FALSE
|
|
|
|
|
|
|
|
# NOTE: This block is a bit redundant, could be improved.
|
|
|
|
echo "Checking for files"
|
|
|
|
if [ -d "$DOWNLOADS_DIR" ]; then
|
|
|
|
if [ -f "$DOWNLOADS_DIR/$IMG_FILENAME" ]; then
|
|
|
|
echo "Found extracted image: $IMG_FILENAME"
|
|
|
|
elif [ -f "$DOWNLOADS_DIR/$ARCHIVE_FILENAME" ]; then
|
|
|
|
should_extract=TRUE
|
|
|
|
else
|
|
|
|
should_download=TRUE; should_extract=TRUE
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "Creading dir: $DOWNLOADS_DIR"
|
|
|
|
mkdir -p "$DOWNLOADS_DIR"
|
|
|
|
should_download=TRUE; should_extract=TRUE
|
|
|
|
fi
|
|
|
|
|
|
|
|
[ $should_download = TRUE ] && download "$ARCHIVE_FILENAME" "${SELECTION_DATA[3]}M" "${SELECTION_DATA[2]}"
|
|
|
|
[ $should_extract = TRUE ] && extract "$ARCHIVE_FILENAME" "${SELECTION_DATA[4]}M"
|
|
|
|
compare_checksum "$DOWNLOADS_DIR/$IMG_FILENAME" "${SELECTION_DATA[5]}"
|
|
|
|
|
|
|
|
# NOTE: Is there a cleaner way to do this?
|
|
|
|
DEVICES=$(list_removable_devices)
|
|
|
|
while [ -z "$DEVICES" ]; do
|
|
|
|
read -rp "No removable devices found. Insert one and press enter"
|
|
|
|
DEVICES=$(list_removable_devices)
|
|
|
|
done
|
|
|
|
|
|
|
|
DEVICE_SELECTION=$(echo "$DEVICES" | fzf)
|
|
|
|
|
|
|
|
|
|
|
|
printf "Will flash %s (%s) to %s\n" \
|
|
|
|
"${SELECTION_DATA[0]}" "${SELECTION_DATA[1]}" "$DEVICE_SELECTION"
|
|
|
|
|
|
|
|
read -rp "Continue? [Y/n]" confirm
|
|
|
|
confirm=${confirm:-Y}
|
|
|
|
|
|
|
|
if [[ $confirm =~ [yY] ]]; then
|
|
|
|
echo "Umounting and flashing"
|
|
|
|
if [ -f "$DOWNLOADS_DIR/$IMG_FILENAME" ] && [ -b "$DEVICE_SELECTION" ]; then
|
|
|
|
for partition in "$DEVICE_SELECTION"?*; do
|
|
|
|
sudo umount "$partition" || true
|
|
|
|
done
|
|
|
|
flash "$DOWNLOADS_DIR/$IMG_FILENAME" "$DEVICE_SELECTION"
|
|
|
|
sync
|
|
|
|
else
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
sudo mkdir -p /mnt/raspi-flash
|
|
|
|
sudo mount "$DEVICE_SELECTION"1 /mnt/raspi-flash
|
|
|
|
|
|
|
|
read -rp "Enable SSH? [Y/n]" enable_ssh
|
|
|
|
enable_ssh=${enable_ssh:-Y}
|
|
|
|
|
|
|
|
if [[ $enable_ssh =~ [yY] ]]; then
|
|
|
|
sudo touch /mnt/raspi-flash/ssh
|
|
|
|
fi
|
|
|
|
|
|
|
|
read -rp "Configure wpa_supplicant? [Y/n]" enable_wifi
|
|
|
|
enable_wifi=${enable_wifi:-Y}
|
|
|
|
|
|
|
|
if [[ $enable_wifi =~ [yY] ]]; then
|
|
|
|
read -rp "Network name: " ssid
|
|
|
|
read -rsp "Password (hidden): " psk
|
|
|
|
printf "\n"
|
|
|
|
read -rp "Country (Two letters. Example: AR): " country
|
|
|
|
[ -f /mnt/raspi-flash/wpa_supplicant.conf ] && \
|
|
|
|
sudo rm /mnt/raspi-flash/wpa_supplicant.conf
|
|
|
|
sudo bash -c 'cat > /mnt/raspi-flash/wpa_supplicant.conf' <<EOF
|
|
|
|
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
|
|
|
|
country=$country
|
|
|
|
update_config=1
|
|
|
|
|
|
|
|
network={
|
|
|
|
ssid="$ssid"
|
|
|
|
psk="$psk"
|
|
|
|
}
|
|
|
|
|
|
|
|
EOF
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Setup user:"
|
|
|
|
read -rp "User name: " username
|
|
|
|
read -rsp "User password (hidden): " userpassword
|
|
|
|
printf "\n"
|
|
|
|
[ -f /mnt/raspi-flash/userconf.txt ] && sudo rm /mnt/raspi-flash/userconf.txt
|
|
|
|
sudo bash -c 'cat > /mnt/raspi-flash/userconf.txt' <<EOF
|
|
|
|
$username:$(echo $userpassword | openssl passwd -6 -stdin)
|
|
|
|
EOF
|
|
|
|
|
|
|
|
sudo umount "$DEVICE_SELECTION"
|
|
|
|
|
|
|
|
sudo rmdir /mnt/raspi-flash
|
|
|
|
echo "Finished successfully!"
|